face+security: Introduce environment variables to set/override transport, pib, and tpm configurations.

- NDN_CLIENT_TRANSPORT: equivalent of transport in client.conf
- NDN_CLIENT_PIB: equivalent of pib in client.conf
- NDN_CLIENT_TPM: equivalent of tpm in client.conf

Whenever an environment variable is set, it takes precedence over any
values specified in the configuration file.

Change-Id: I44c2347168616387a0489b6bf5c2c3a12db29863
Refs: #2925, #2514
diff --git a/src/face.cpp b/src/face.cpp
index 9f64aa6..51519c9 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -91,32 +91,42 @@
   // transport=unix:///var/run/nfd.sock
   // transport=tcp://localhost:6363
 
-  ConfigFile config;
-  const auto& transportUri = config.getParsedConfiguration()
-                               .get_optional<std::string>("transport");
-  if (!transportUri) {
+  std::string transportUri;
+
+  if (getenv("NDN_CLIENT_TRANSPORT") != nullptr) {
+    transportUri = getenv("NDN_CLIENT_TRANSPORT");
+  }
+  else {
+    ConfigFile config;
+    transportUri = config.getParsedConfiguration().get<std::string>("transport", "");
+  }
+
+  if (transportUri.empty()) {
     // transport not specified, use default Unix transport.
-    return UnixTransport::create(config);
+    return UnixTransport::create("");
   }
 
   std::string protocol;
   try {
-    util::FaceUri uri(*transportUri);
+    util::FaceUri uri(transportUri);
     protocol = uri.getScheme();
+
+    if (protocol == "unix") {
+      return UnixTransport::create(transportUri);
+    }
+    else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") {
+      return TcpTransport::create(transportUri);
+    }
+    else {
+      BOOST_THROW_EXCEPTION(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
+    }
+  }
+  catch (const Transport::Error& error) {
+    BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
   }
   catch (const util::FaceUri::Error& error) {
     BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
   }
-
-  if (protocol == "unix") {
-    return UnixTransport::create(config);
-  }
-  else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") {
-    return TcpTransport::create(config);
-  }
-  else {
-    BOOST_THROW_EXCEPTION(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
-  }
 }
 
 void
diff --git a/src/security/key-chain.cpp b/src/security/key-chain.cpp
index c1c605a..e6b1ff0 100644
--- a/src/security/key-chain.cpp
+++ b/src/security/key-chain.cpp
@@ -123,11 +123,29 @@
   , m_tpm(nullptr)
   , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
 {
-  ConfigFile config;
-  const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
+  std::string pibLocator;
+  std::string tpmLocator;
 
-  std::string pibLocator = parsed.get<std::string>("pib", "");
-  std::string tpmLocator = parsed.get<std::string>("tpm", "");
+  if (getenv("NDN_CLIENT_PIB") != nullptr) {
+    pibLocator = getenv("NDN_CLIENT_PIB");
+  }
+
+  if (getenv("NDN_CLIENT_TPM") != nullptr) {
+    tpmLocator = getenv("NDN_CLIENT_TPM");
+  }
+
+  if (pibLocator.empty() || tpmLocator.empty()) {
+    ConfigFile config;
+    const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
+
+    if (pibLocator.empty()) {
+      pibLocator = parsed.get<std::string>("pib", "");
+    }
+
+    if (tpmLocator.empty()) {
+      tpmLocator = parsed.get<std::string>("tpm", "");
+    }
+  }
 
   initialize(pibLocator, tpmLocator, false);
 }
diff --git a/src/security/pib-sqlite3.cpp b/src/security/pib-sqlite3.cpp
index b20ee7c..01e80f7 100644
--- a/src/security/pib-sqlite3.cpp
+++ b/src/security/pib-sqlite3.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -216,16 +216,24 @@
   // Determine the path of PIB DB
   boost::filesystem::path actualDir;
   if (dir == "") {
-    if (getenv("HOME") == nullptr)
-      BOOST_THROW_EXCEPTION(PibImpl::Error("Environment variable HOME is not set"));
-
-    actualDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
-    boost::filesystem::create_directories(actualDir);
+#ifdef NDN_CXX_HAVE_TESTS
+    if (getenv("TEST_HOME") != nullptr) {
+      actualDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn";
+    }
+    else
+#endif // NDN_CXX_HAVE_TESTS
+    if (getenv("HOME") != nullptr) {
+      actualDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
+    }
+    else {
+      actualDir = boost::filesystem::path(".") / ".ndn";
+    }
   }
   else {
     actualDir = boost::filesystem::path(dir);
-    boost::filesystem::create_directories(actualDir);
   }
+  boost::filesystem::create_directories(actualDir);
+
   // Open PIB
   int result = sqlite3_open_v2((actualDir / "pib.db").c_str(), &m_database,
                                SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
diff --git a/src/security/sec-public-info-sqlite3.cpp b/src/security/sec-public-info-sqlite3.cpp
index 462f215..9974336 100644
--- a/src/security/sec-public-info-sqlite3.cpp
+++ b/src/security/sec-public-info-sqlite3.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -114,10 +114,23 @@
   , m_database(nullptr)
 {
   boost::filesystem::path identityDir;
-  if (dir == "")
-    identityDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
-  else
-    identityDir = boost::filesystem::path(dir) / ".ndn";
+  if (dir == "") {
+#ifdef NDN_CXX_HAVE_TESTS
+    if (getenv("TEST_HOME") != nullptr) {
+      identityDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn";
+    }
+    else
+#endif // NDN_CXX_HAVE_TESTS
+    if (getenv("HOME") != nullptr) {
+      identityDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
+    }
+    else {
+      identityDir = boost::filesystem::path(".") / ".ndn";
+    }
+  }
+  else {
+    identityDir = boost::filesystem::path(dir);
+  }
   boost::filesystem::create_directories(identityDir);
 
   /// @todo Add define for windows/unix in wscript. The following may completely fail on windows
diff --git a/src/security/sec-tpm-file.cpp b/src/security/sec-tpm-file.cpp
index e20fa94..306a062 100644
--- a/src/security/sec-tpm-file.cpp
+++ b/src/security/sec-tpm-file.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -51,11 +51,26 @@
   explicit
   Impl(const string& dir)
   {
-    if (dir.empty())
-      m_keystorePath = boost::filesystem::path(getenv("HOME")) / ".ndn" / "ndnsec-tpm-file";
-    else
-      m_keystorePath = boost::filesystem::path(dir) / ".ndn" / "ndnsec-tpm-file";
+    boost::filesystem::path actualDir;
+    if (dir.empty()) {
+#ifdef NDN_CXX_HAVE_TESTS
+      if (getenv("TEST_HOME") != nullptr) {
+        actualDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn";
+      }
+      else
+#endif // NDN_CXX_HAVE_TESTS
+      if (getenv("HOME") != nullptr) {
+        actualDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
+      }
+      else {
+        actualDir = boost::filesystem::path(".") / ".ndn";
+      }
+    }
+    else {
+      actualDir = boost::filesystem::path(dir);
+    }
 
+    m_keystorePath = actualDir / "ndnsec-tpm-file";
     boost::filesystem::create_directories(m_keystorePath);
   }
 
diff --git a/src/transport/tcp-transport.cpp b/src/transport/tcp-transport.cpp
index afde1e0..20952ab 100644
--- a/src/transport/tcp-transport.cpp
+++ b/src/transport/tcp-transport.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -38,27 +38,28 @@
 }
 
 shared_ptr<TcpTransport>
-TcpTransport::create(const ConfigFile& config)
+TcpTransport::create(const std::string& uri)
 {
-  const auto hostAndPort(getDefaultSocketHostAndPort(config));
+  const auto hostAndPort(getSocketHostAndPortFromUri(uri));
   return make_shared<TcpTransport>(hostAndPort.first, hostAndPort.second);
 }
 
 std::pair<std::string, std::string>
-TcpTransport::getDefaultSocketHostAndPort(const ConfigFile& config)
+TcpTransport::getSocketHostAndPortFromUri(const std::string& uriString)
 {
-  const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
-
   std::string host = "localhost";
   std::string port = "6363";
 
+  if (uriString.empty()) {
+    return {host, port};
+  }
+
   try {
-    const util::FaceUri uri(parsed.get<std::string>("transport", "tcp://" + host));
+    const util::FaceUri uri(uriString);
 
     const std::string scheme = uri.getScheme();
     if (scheme != "tcp" && scheme != "tcp4" && scheme != "tcp6") {
-      BOOST_THROW_EXCEPTION(Transport::Error("Cannot create TcpTransport from \"" +
-                                             scheme + "\" URI"));
+      BOOST_THROW_EXCEPTION(Error("Cannot create TcpTransport from \"" + scheme + "\" URI"));
     }
 
     if (!uri.getHost().empty()) {
@@ -70,7 +71,7 @@
     }
   }
   catch (const util::FaceUri::Error& error) {
-    BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
+    BOOST_THROW_EXCEPTION(Error(error.what()));
   }
 
   return {host, port};
diff --git a/src/transport/tcp-transport.hpp b/src/transport/tcp-transport.hpp
index 0ddd1a9..b0b5124 100644
--- a/src/transport/tcp-transport.hpp
+++ b/src/transport/tcp-transport.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2014 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -62,13 +62,18 @@
   virtual void
   send(const Block& header, const Block& payload);
 
+  /**
+   * @brief Create transport with parameters defined in URI
+   *
+   * @throws Transport::Error if incorrect URI or unsupported protocol is specified
+   */
   static shared_ptr<TcpTransport>
-  create(const ConfigFile& config);
+  create(const std::string& uri);
 
 NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
 
   static std::pair<std::string, std::string>
-  getDefaultSocketHostAndPort(const ConfigFile& config);
+  getSocketHostAndPortFromUri(const std::string& uri);
 
 private:
   std::string m_host;
diff --git a/src/transport/unix-transport.cpp b/src/transport/unix-transport.cpp
index 6b86a34..0c63960 100644
--- a/src/transport/unix-transport.cpp
+++ b/src/transport/unix-transport.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -39,46 +39,38 @@
 }
 
 std::string
-UnixTransport::getDefaultSocketName(const ConfigFile& config)
+UnixTransport::getSocketNameFromUri(const std::string& uriString)
 {
-  const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
-
-  try
-    {
-      const util::FaceUri uri(parsed.get<std::string>("transport"));
-
-      if (uri.getScheme() != "unix")
-        {
-          BOOST_THROW_EXCEPTION(Transport::Error("Cannot create UnixTransport from \"" +
-                                                 uri.getScheme() + "\" URI"));
-        }
-
-      if (!uri.getPath().empty())
-        {
-          return uri.getPath();
-        }
-    }
-  catch (const boost::property_tree::ptree_bad_path& error)
-    {
-      // no transport specified
-    }
-  catch (const boost::property_tree::ptree_bad_data& error)
-    {
-      BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
-    }
-  catch (const util::FaceUri::Error& error)
-    {
-      BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
-    }
-
   // Assume the default nfd.sock location.
-  return "/var/run/nfd.sock";
+  std::string path = "/var/run/nfd.sock";
+
+  if (uriString.empty()) {
+    return path;
+  }
+
+  try {
+    const util::FaceUri uri(uriString);
+
+    if (uri.getScheme() != "unix") {
+      BOOST_THROW_EXCEPTION(Error("Cannot create UnixTransport from \"" +
+                                  uri.getScheme() + "\" URI"));
+    }
+
+    if (!uri.getPath().empty()) {
+      path = uri.getPath();
+    }
+  }
+  catch (const util::FaceUri::Error& error) {
+    BOOST_THROW_EXCEPTION(Error(error.what()));
+  }
+
+  return path;
 }
 
 shared_ptr<UnixTransport>
-UnixTransport::create(const ConfigFile& config)
+UnixTransport::create(const std::string& uri)
 {
-  return make_shared<UnixTransport>(getDefaultSocketName(config));
+  return make_shared<UnixTransport>(getSocketNameFromUri(uri));
 }
 
 void
@@ -131,4 +123,4 @@
   m_impl->resume();
 }
 
-}
+} // namespace ndn
diff --git a/src/transport/unix-transport.hpp b/src/transport/unix-transport.hpp
index 5a73047..6d16c26 100644
--- a/src/transport/unix-transport.hpp
+++ b/src/transport/unix-transport.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2014 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -69,18 +69,18 @@
   virtual void
   send(const Block& header, const Block& payload);
 
+  /**
+   * @brief Create transport with parameters defined in URI
+   *
+   * @throws Transport::Error if incorrect URI or unsupported protocol is specified
+   */
   static shared_ptr<UnixTransport>
-  create(const ConfigFile& config);
+  create(const std::string& uri);
 
 NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-  /**
-   * Determine the default NFD unix socket
-   *
-   * @returns transport value if present in config, else /var/run/nfd.sock
-   * @throws ConfigFile::Error if fail to parse value of a present "transport" field
-   */
+
   static std::string
-  getDefaultSocketName(const ConfigFile& config);
+  getSocketNameFromUri(const std::string& uri);
 
 private:
   std::string m_unixSocket;
diff --git a/src/util/config-file.hpp b/src/util/config-file.hpp
index 5c71dde..2bb6c2d 100644
--- a/src/util/config-file.hpp
+++ b/src/util/config-file.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2014 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -31,6 +31,20 @@
 
 namespace ndn {
 
+/**
+ * @brief System configuration file for NDN platform
+ *
+ * The config file controls the default transport to connect to NDN forwarder, type and
+ * location of PIB and TPM.
+ *
+ * Looking for the configuration file in these well-known locations (in order):
+ *
+ * - `$HOME/.ndn/client.conf`
+ * - `@SYSCONFDIR@/ndn/client.conf`
+ * - `/etc/ndn/client.conf`
+ *
+ * @sa Manpage of ndn-client.conf
+ */
 class ConfigFile : noncopyable
 {
 public:
@@ -48,7 +62,7 @@
   typedef boost::property_tree::ptree Parsed;
 
   /**
-   * Locate, open, and parse a library configuration file.
+   * @brief Locate, open, and parse a library configuration file.
    *
    * @throws ConfigFile::Error on parse error
    */
@@ -71,7 +85,8 @@
   close();
 
   /**
-   * Parse a previously discovered and opened configuration file.
+   * @brief Parse a previously discovered and opened configuration file.
+   *
    * For convenience this method will attempt to open the file
    * if it has previously been located, but open() has not been called.
    *
@@ -83,11 +98,13 @@
   parse();
 
   /**
-   * Looking for the configuration file in these well-known locations:
+   * @brief Find the configuration file in well-known locations
    *
-   * 1. $HOME/.ndn/client.conf
-   * 2. @SYSCONFDIR@/ndn/client.conf
-   * 3. /etc/ndn/client.conf
+   * The well-known locations include (in order):
+   *
+   * - `$HOME/.ndn/client.conf`
+   * - `@SYSCONFDIR@/ndn/client.conf`
+   * - `/etc/ndn/client.conf`
    *
    * @return path to preferred configuration (according to above order) or empty path on failure
    */