util, transport: add configuration file support and make default unix socket configurable

add sample library configuration file

refs: #1364

Change-Id: I3cb36d078aa3f0b0a50d9a83a521e95448df0a93
diff --git a/src/transport/transport.hpp b/src/transport/transport.hpp
index da06da4..e678491 100644
--- a/src/transport/transport.hpp
+++ b/src/transport/transport.hpp
@@ -14,7 +14,12 @@
 
 class Transport {
 public:
-  struct Error : public std::runtime_error { inline Error(const boost::system::error_code &code, const std::string &msg); };
+  class Error : public std::runtime_error
+  {
+  public:
+    inline Error(const boost::system::error_code &code, const std::string &msg);
+    inline Error(const std::string& msg);
+  };
   
   typedef ptr_lib::function<void (const Block &wire)> ReceiveCallback;
   typedef ptr_lib::function<void ()> ErrorCallback;
@@ -89,12 +94,19 @@
 {
 }
 
-inline Transport::Error::Error(const boost::system::error_code& code, const std::string& msg)
+inline
+Transport::Error::Error(const boost::system::error_code& code, const std::string& msg)
   : std::runtime_error(msg + (code.value() ? " (" + code.category().message(code.value()) + ")" : ""))
 {
 }
 
 inline
+Transport::Error::Error(const std::string& msg)
+  : std::runtime_error(msg)
+{
+}
+
+inline
 Transport::~Transport()
 {
 }
diff --git a/src/transport/unix-transport.cpp b/src/transport/unix-transport.cpp
index 33fad1c..ad6db2c 100644
--- a/src/transport/unix-transport.cpp
+++ b/src/transport/unix-transport.cpp
@@ -13,14 +13,6 @@
 
 namespace ndn {
 
-UnixTransport::UnixTransport()
-{
-  if (std::getenv("NFD") != 0)
-      m_unixSocket = "/var/run/nfd.sock";
-  else
-      m_unixSocket = "/tmp/.ndnd.sock";
-}
-
 UnixTransport::UnixTransport(const std::string& unixSocket)
   : m_unixSocket(unixSocket)
 {
@@ -30,6 +22,48 @@
 {
 }
 
+std::string
+UnixTransport::getDefaultSocketName(const ConfigFile& config)
+{
+  const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
+  try
+    {
+      return parsed.get<std::string>("unix_socket");
+    }
+  catch (const boost::property_tree::ptree_bad_path& error)
+    {
+      // unix_socket not present, continue
+    }
+  catch (const boost::property_tree::ptree_bad_data& error)
+    {
+      throw ConfigFile::Error(error.what());
+    }
+
+  // no unix_socket specified so the default socket name
+  // depends on the protocol we're using
+  try
+    {
+      const std::string protocol = parsed.get<std::string>("protocol");
+      if (protocol == "ndnd-tlv-0.7")
+        {
+          return "/tmp/.ndnd.sock";
+        }
+    }
+  catch (boost::property_tree::ptree_bad_path& error)
+    {
+      return "/var/run/nfd.sock";
+    }
+  catch (boost::property_tree::ptree_bad_data& error)
+    {
+      throw ConfigFile::Error(error.what());
+    }
+
+  // A we made here, then there's no unix_socket specified in the configuration
+  // file. A protocol is present, but it's not ndnd.
+  // Assume the default nfd.sock location.
+  return "/var/run/nfd.sock";
+}
+
 void
 UnixTransport::connect(boost::asio::io_service& ioService,
                        const ReceiveCallback& receiveCallback)
diff --git a/src/transport/unix-transport.hpp b/src/transport/unix-transport.hpp
index f8114f5..47636fa 100644
--- a/src/transport/unix-transport.hpp
+++ b/src/transport/unix-transport.hpp
@@ -9,6 +9,7 @@
 
 #include "../common.hpp"
 #include "transport.hpp"
+#include "../util/config-file.hpp"
 
 // forward declaration
 namespace boost { namespace asio { namespace local { class stream_protocol; } } }
@@ -22,9 +23,15 @@
 class UnixTransport : public Transport
 {
 public:
-  UnixTransport();
 
+  /**
+   * Create Unix transport based on the socket specified
+   * in a well-known configuration file or fallback to /var/run/nfd.sock
+   *
+   * @throws Throws UnixTransport::Error on failure to parse a discovered configuration file
+   */
   UnixTransport(const std::string& unixSocket);
+
   ~UnixTransport();
 
   // from Transport
@@ -46,7 +53,16 @@
 
   virtual void
   send(const Block& header, const Block& payload);
-  
+
+  /**
+   * Determine the default NFD unix socket
+   *
+   * @returns unix_socket value if present in config, else /var/run/nfd.sock
+   * @throws ConfigFile::Error if fail to parse value of a present "unix_socket" field
+   */
+  static std::string
+  getDefaultSocketName(const ConfigFile& config);
+
 private:
   std::string m_unixSocket;