core: extend FaceUri with fd, ether, dev schemes

refs #1396

Change-Id: I6680eb2013c335a14c9fa76b965c2d1e63202334
diff --git a/daemon/core/face-uri.cpp b/daemon/core/face-uri.cpp
index cc6c8c8..14751d6 100644
--- a/daemon/core/face-uri.cpp
+++ b/daemon/core/face-uri.cpp
@@ -6,6 +6,10 @@
 
 #include "face-uri.hpp"
 #include "core/logger.hpp"
+#ifdef HAVE_PCAP
+#include "face/ethernet.hpp"
+#endif // HAVE_PCAP
+
 #include <boost/regex.hpp>
 
 NFD_LOG_INIT("FaceUri");
@@ -35,30 +39,35 @@
   m_port.clear();
   m_path.clear();
 
-  boost::regex protocolExp("(\\w+\\d?)://([^/]*)(\\/[^?]*)?");
+  static const boost::regex protocolExp("(\\w+\\d?)://([^/]*)(\\/[^?]*)?");
   boost::smatch protocolMatch;
   if (!boost::regex_match(uri, protocolMatch, protocolExp)) {
     return false;
   }
   m_scheme = protocolMatch[1];
+  const std::string& authority = protocolMatch[2];
   m_path = protocolMatch[3];
 
-  const std::string& authority = protocolMatch[2];
+  // pattern for IPv6 address enclosed in [ ], with optional port number
+  static const boost::regex v6Exp("^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
+  // pattern for Ethernet address in standard hex-digits-and-colons notation
+  static const boost::regex etherExp("^((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))$");
+  // pattern for IPv4/hostname/fd/ifname, with optional port number
+  static const boost::regex v4HostExp("^([^:]+)(?:\\:(\\d+))?$");
 
-  boost::regex v6Exp("^\\[(([a-fA-F0-9:]+))\\](:(\\d+))?$"); // [host]:port
-  boost::regex v4Exp("^((\\d+\\.){3}\\d+)(:(\\d+))?$");
-  boost::regex hostExp("^(([^:]*))(:(\\d+))?$"); // host:port
-
-  boost::smatch match;
-  m_isV6 = boost::regex_match(authority, match, v6Exp);
-  if (m_isV6 ||
-      boost::regex_match(authority, match, v4Exp) ||
-      boost::regex_match(authority, match, hostExp)) {
-    m_host = match[1];
-    m_port = match[4];
+  if (authority.empty()) {
+    // UNIX, internal
   }
   else {
-    if (m_path.empty()) {
+    boost::smatch match;
+    m_isV6 = boost::regex_match(authority, match, v6Exp);
+    if (m_isV6 ||
+        boost::regex_match(authority, match, etherExp) ||
+        boost::regex_match(authority, match, v4HostExp)) {
+      m_host = match[1];
+      m_port = match[2];
+    }
+    else {
       return false;
     }
   }
@@ -84,11 +93,40 @@
   m_port = boost::lexical_cast<std::string>(endpoint.port());
 }
 
+#ifdef HAVE_UNIX_SOCKETS
 FaceUri::FaceUri(const boost::asio::local::stream_protocol::endpoint& endpoint)
   : m_isV6(false)
 {
   m_scheme = "unix";
   m_path = endpoint.path();
 }
+#endif // HAVE_UNIX_SOCKETS
+
+FaceUri
+FaceUri::fromFd(int fd)
+{
+  FaceUri uri;
+  uri.m_scheme = "fd";
+  uri.m_host = boost::lexical_cast<std::string>(fd);
+  return uri;
+}
+
+#ifdef HAVE_PCAP
+FaceUri::FaceUri(const ethernet::Address& address)
+  : m_isV6(false)
+{
+  m_scheme = "ether";
+  m_host = address.toString(':');
+}
+#endif // HAVE_PCAP
+
+FaceUri
+FaceUri::fromDev(const std::string& ifname)
+{
+  FaceUri uri;
+  uri.m_scheme = "dev";
+  uri.m_host = ifname;
+  return uri;
+}
 
 } // namespace nfd