face+mgmt: enable local fields through ProtocolFactory::createFace

refs #3731

Change-Id: I569dae59cda150ffcb1c0ff1d01a575d8850beca
diff --git a/daemon/face/ethernet-factory.cpp b/daemon/face/ethernet-factory.cpp
index 85f00f1..cfb4b79 100644
--- a/daemon/face/ethernet-factory.cpp
+++ b/daemon/face/ethernet-factory.cpp
@@ -58,6 +58,7 @@
 void
 EthernetFactory::createFace(const FaceUri& uri,
                             ndn::nfd::FacePersistency persistency,
+                            bool wantLocalFieldsEnabled,
                             const FaceCreatedCallback& onCreated,
                             const FaceCreationFailedCallback& onFailure)
 {
diff --git a/daemon/face/ethernet-factory.hpp b/daemon/face/ethernet-factory.hpp
index f29e09a..8e11024 100644
--- a/daemon/face/ethernet-factory.hpp
+++ b/daemon/face/ethernet-factory.hpp
@@ -79,6 +79,7 @@
   virtual void
   createFace(const FaceUri& uri,
              ndn::nfd::FacePersistency persistency,
+             bool wantLocalFieldsEnabled,
              const FaceCreatedCallback& onCreated,
              const FaceCreationFailedCallback& onFailure) override;
 
diff --git a/daemon/face/protocol-factory.hpp b/daemon/face/protocol-factory.hpp
index 6af5bb8..ee19063 100644
--- a/daemon/face/protocol-factory.hpp
+++ b/daemon/face/protocol-factory.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -55,14 +55,20 @@
    * This method should automatically choose channel, based on supplied FaceUri
    * and create face.
    *
-   * \throw Error Factory does not support connect operation
-   * \throw Error specified \p persistency is not supported
+   * \param uri remote URI of the new face
+   * \param persistency persistency of the new face
+   * \param wantLocalFieldsEnabled whether local fields should be enabled on the face
+   * \param onCreated callback if face creation succeeds
+   *                  If a face with the same remote URI already exists, its persistency and
+   *                  LocalFieldsEnabled setting will not be modified.
+   * \param onFailure callback if face creation fails
    */
   virtual void
   createFace(const FaceUri& uri,
              ndn::nfd::FacePersistency persistency,
+             bool wantLocalFieldsEnabled,
              const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onConnectFailed) = 0;
+             const FaceCreationFailedCallback& onFailure) = 0;
 
   virtual std::vector<shared_ptr<const Channel>>
   getChannels() const = 0;
diff --git a/daemon/face/tcp-channel.cpp b/daemon/face/tcp-channel.cpp
index 163b0e9..656b671 100644
--- a/daemon/face/tcp-channel.cpp
+++ b/daemon/face/tcp-channel.cpp
@@ -66,6 +66,7 @@
 
 void
 TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
+                    bool wantLocalFieldsEnabled,
                     const FaceCreatedCallback& onFaceCreated,
                     const FaceCreationFailedCallback& onConnectFailed,
                     const time::seconds& timeout/* = time::seconds(4)*/)
@@ -83,8 +84,8 @@
 
   clientSocket->async_connect(remoteEndpoint,
                               bind(&TcpChannel::handleConnect, this,
-                                   boost::asio::placeholders::error,
-                                   clientSocket, connectTimeoutEvent,
+                                   boost::asio::placeholders::error, clientSocket,
+                                   wantLocalFieldsEnabled, connectTimeoutEvent,
                                    onFaceCreated, onConnectFailed));
 }
 
@@ -96,8 +97,9 @@
 
 void
 TcpChannel::createFace(ip::tcp::socket&& socket,
-                       const FaceCreatedCallback& onFaceCreated,
-                       bool isOnDemand)
+                       bool isOnDemand,
+                       bool wantLocalFieldsEnabled,
+                       const FaceCreatedCallback& onFaceCreated)
 {
   shared_ptr<Face> face;
   tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
@@ -107,7 +109,12 @@
     auto persistency = isOnDemand ? ndn::nfd::FACE_PERSISTENCY_ON_DEMAND
                                   : ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
     auto linkService = make_unique<face::GenericLinkService>();
+    auto options = linkService->getOptions();
+    options.allowLocalFields = wantLocalFieldsEnabled;
+    linkService->setOptions(options);
+
     auto transport = make_unique<face::TcpTransport>(std::move(socket), persistency);
+
     face = make_shared<Face>(std::move(linkService), std::move(transport));
 
     m_channelFaces[remoteEndpoint] = face;
@@ -157,7 +164,7 @@
 
   NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connection from " << m_acceptSocket.remote_endpoint());
 
-  createFace(std::move(m_acceptSocket), onFaceCreated, true);
+  createFace(std::move(m_acceptSocket), true, false, onFaceCreated);
 
   // prepare accepting the next connection
   accept(onFaceCreated, onAcceptFailed);
@@ -166,6 +173,7 @@
 void
 TcpChannel::handleConnect(const boost::system::error_code& error,
                           const shared_ptr<ip::tcp::socket>& socket,
+                          bool wantLocalFieldsEnabled,
                           const scheduler::EventId& connectTimeoutEvent,
                           const FaceCreatedCallback& onFaceCreated,
                           const FaceCreationFailedCallback& onConnectFailed)
@@ -195,7 +203,7 @@
 
   NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connected to " << socket->remote_endpoint());
 
-  createFace(std::move(*socket), onFaceCreated, false);
+  createFace(std::move(*socket), false, wantLocalFieldsEnabled, onFaceCreated);
 }
 
 void
diff --git a/daemon/face/tcp-channel.hpp b/daemon/face/tcp-channel.hpp
index c819014..1b2fd93 100644
--- a/daemon/face/tcp-channel.hpp
+++ b/daemon/face/tcp-channel.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -73,6 +73,7 @@
    */
   void
   connect(const tcp::Endpoint& remoteEndpoint,
+          bool wantLocalFieldsEnabled,
           const FaceCreatedCallback& onFaceCreated,
           const FaceCreationFailedCallback& onConnectFailed,
           const time::seconds& timeout = time::seconds(4));
@@ -89,8 +90,9 @@
 private:
   void
   createFace(boost::asio::ip::tcp::socket&& socket,
-             const FaceCreatedCallback& onFaceCreated,
-             bool isOnDemand);
+             bool isOnDemand,
+             bool wantLocalFieldsEnabled,
+             const FaceCreatedCallback& onFaceCreated);
 
   void
   accept(const FaceCreatedCallback& onFaceCreated,
@@ -104,6 +106,7 @@
   void
   handleConnect(const boost::system::error_code& error,
                 const shared_ptr<boost::asio::ip::tcp::socket>& socket,
+                bool wantLocalFieldsEnabled,
                 const scheduler::EventId& connectTimeoutEvent,
                 const FaceCreatedCallback& onFaceCreated,
                 const FaceCreationFailedCallback& onConnectFailed);
diff --git a/daemon/face/tcp-factory.cpp b/daemon/face/tcp-factory.cpp
index 5c96492..8ae2337 100644
--- a/daemon/face/tcp-factory.cpp
+++ b/daemon/face/tcp-factory.cpp
@@ -99,14 +99,15 @@
 void
 TcpFactory::createFace(const FaceUri& uri,
                        ndn::nfd::FacePersistency persistency,
+                       bool wantLocalFieldsEnabled,
                        const FaceCreatedCallback& onCreated,
-                       const FaceCreationFailedCallback& onConnectFailed)
+                       const FaceCreationFailedCallback& onFailure)
 {
   BOOST_ASSERT(uri.isCanonical());
 
   if (persistency != ndn::nfd::FACE_PERSISTENCY_PERSISTENT) {
     NFD_LOG_TRACE("createFace only supports FACE_PERSISTENCY_PERSISTENT");
-    onConnectFailed(406, "Outgoing TCP faces only support persistent persistency");
+    onFailure(406, "Outgoing TCP faces only support persistent persistency");
     return;
   }
 
@@ -115,14 +116,20 @@
 
   if (endpoint.address().is_multicast()) {
    NFD_LOG_TRACE("createFace cannot create multicast faces");
-   onConnectFailed(406, "Cannot create multicast TCP faces");
+   onFailure(406, "Cannot create multicast TCP faces");
    return;
   }
 
   if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
     NFD_LOG_TRACE("Requested endpoint is prohibited "
                   "(reserved by NFD or disallowed by face management protocol)");
-    onConnectFailed(406, "Requested endpoint is prohibited");
+    onFailure(406, "Requested endpoint is prohibited");
+    return;
+  }
+
+  if (wantLocalFieldsEnabled && !endpoint.address().is_loopback()) {
+    NFD_LOG_TRACE("createFace cannot create non-local face with local fields enabled");
+    onFailure(406, "Local fields can only be enabled on faces with local scope");
     return;
   }
 
@@ -130,13 +137,13 @@
   for (const auto& i : m_channels) {
     if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
         (i.first.address().is_v6() && endpoint.address().is_v6())) {
-      i.second->connect(endpoint, onCreated, onConnectFailed);
+      i.second->connect(endpoint, wantLocalFieldsEnabled, onCreated, onFailure);
       return;
     }
   }
 
   NFD_LOG_TRACE("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
-  onConnectFailed(504, "No channels available to connect");
+  onFailure(504, "No channels available to connect");
 }
 
 std::vector<shared_ptr<const Channel>>
diff --git a/daemon/face/tcp-factory.hpp b/daemon/face/tcp-factory.hpp
index 126aef2..2ed6ad1 100644
--- a/daemon/face/tcp-factory.hpp
+++ b/daemon/face/tcp-factory.hpp
@@ -35,19 +35,6 @@
 {
 public:
   /**
-   * \brief Exception of TcpFactory
-   */
-  class Error : public ProtocolFactory::Error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : ProtocolFactory::Error(what)
-    {
-    }
-  };
-
-  /**
    * \brief Create TCP-based channel using tcp::Endpoint
    *
    * tcp::Endpoint is really an alias for boost::asio::ip::tcp::endpoint.
@@ -59,8 +46,6 @@
    * \returns always a valid pointer to a TcpChannel object, an exception
    *          is thrown if it cannot be created.
    *
-   * \throws TcpFactory::Error
-   *
    * \see http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/reference/ip__tcp/endpoint.html
    *      for details on ways to create tcp::Endpoint
    */
@@ -73,7 +58,7 @@
    * This method is just a helper that converts a string representation of localIp and port to
    * tcp::Endpoint and calls the other createChannel overload.
    *
-   * \throws TcpFactory::Error or std::runtime_error
+   * \throws std::runtime_error
    */
   shared_ptr<TcpChannel>
   createChannel(const std::string& localIp, const std::string& localPort);
@@ -82,8 +67,9 @@
   virtual void
   createFace(const FaceUri& uri,
              ndn::nfd::FacePersistency persistency,
+             bool wantLocalFieldsEnabled,
              const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onConnectFailed) override;
+             const FaceCreationFailedCallback& onFailure) override;
 
   virtual std::vector<shared_ptr<const Channel>>
   getChannels() const override;
diff --git a/daemon/face/udp-channel.cpp b/daemon/face/udp-channel.cpp
index 9b66b0d..64907be 100644
--- a/daemon/face/udp-channel.cpp
+++ b/daemon/face/udp-channel.cpp
@@ -146,8 +146,10 @@
 {
   auto it = m_channelFaces.find(remoteEndpoint);
   if (it != m_channelFaces.end()) {
-    // we already have a face for this endpoint, just reuse it
+    // we already have a face for this endpoint, so reuse it
     auto face = it->second;
+
+    // TODO #3232: Remove persistency transitions from faces/create
     // only on-demand -> persistent -> permanent transition is allowed
     bool isTransitionAllowed = persistency != face->getPersistency() &&
                                (face->getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND ||
diff --git a/daemon/face/udp-factory.cpp b/daemon/face/udp-factory.cpp
index 499c72c..88ac221 100644
--- a/daemon/face/udp-factory.cpp
+++ b/daemon/face/udp-factory.cpp
@@ -233,14 +233,15 @@
 void
 UdpFactory::createFace(const FaceUri& uri,
                        ndn::nfd::FacePersistency persistency,
+                       bool wantLocalFieldsEnabled,
                        const FaceCreatedCallback& onCreated,
-                       const FaceCreationFailedCallback& onConnectFailed)
+                       const FaceCreationFailedCallback& onFailure)
 {
   BOOST_ASSERT(uri.isCanonical());
 
   if (persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
     NFD_LOG_TRACE("createFace does not support FACE_PERSISTENCY_ON_DEMAND");
-    onConnectFailed(406, "Outgoing unicast UDP faces do not support on-demand persistency");
+    onFailure(406, "Outgoing unicast UDP faces do not support on-demand persistency");
     return;
   }
 
@@ -249,14 +250,21 @@
 
   if (endpoint.address().is_multicast()) {
     NFD_LOG_TRACE("createFace does not support multicast faces");
-    onConnectFailed(406, "Cannot create multicast UDP faces");
+    onFailure(406, "Cannot create multicast UDP faces");
     return;
   }
 
   if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
     NFD_LOG_TRACE("Requested endpoint is prohibited "
                   "(reserved by this NFD or disallowed by face management protocol)");
-    onConnectFailed(406, "Requested endpoint is prohibited");
+    onFailure(406, "Requested endpoint is prohibited");
+    return;
+  }
+
+  if (wantLocalFieldsEnabled) {
+    // UDP faces are never local
+    NFD_LOG_TRACE("createFace cannot create non-local face with local fields enabled");
+    onFailure(406, "Local fields can only be enabled on faces with local scope");
     return;
   }
 
@@ -264,13 +272,13 @@
   for (const auto& i : m_channels) {
     if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
         (i.first.address().is_v6() && endpoint.address().is_v6())) {
-      i.second->connect(endpoint, persistency, onCreated, onConnectFailed);
+      i.second->connect(endpoint, persistency, onCreated, onFailure);
       return;
     }
   }
 
   NFD_LOG_TRACE("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
-  onConnectFailed(504, "No channels available to connect");
+  onFailure(504, "No channels available to connect");
 }
 
 std::vector<shared_ptr<const Channel>>
diff --git a/daemon/face/udp-factory.hpp b/daemon/face/udp-factory.hpp
index bda8ac5..c788a3f 100644
--- a/daemon/face/udp-factory.hpp
+++ b/daemon/face/udp-factory.hpp
@@ -149,8 +149,9 @@
   virtual void
   createFace(const FaceUri& uri,
              ndn::nfd::FacePersistency persistency,
+             bool wantLocalFieldsEnabled,
              const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onConnectFailed) override;
+             const FaceCreationFailedCallback& onFailure) override;
 
   virtual std::vector<shared_ptr<const Channel>>
   getChannels() const override;
diff --git a/daemon/face/unix-stream-factory.cpp b/daemon/face/unix-stream-factory.cpp
index b85953e..bfbab44 100644
--- a/daemon/face/unix-stream-factory.cpp
+++ b/daemon/face/unix-stream-factory.cpp
@@ -48,10 +48,11 @@
 void
 UnixStreamFactory::createFace(const FaceUri& uri,
                               ndn::nfd::FacePersistency persistency,
+                              bool wantLocalFieldsEnabled,
                               const FaceCreatedCallback& onCreated,
-                              const FaceCreationFailedCallback& onConnectFailed)
+                              const FaceCreationFailedCallback& onFailure)
 {
-  onConnectFailed(406, "Unsupported protocol");
+  onFailure(406, "Unsupported protocol");
 }
 
 std::vector<shared_ptr<const Channel>>
diff --git a/daemon/face/unix-stream-factory.hpp b/daemon/face/unix-stream-factory.hpp
index 2f899b6..07a8317 100644
--- a/daemon/face/unix-stream-factory.hpp
+++ b/daemon/face/unix-stream-factory.hpp
@@ -35,19 +35,6 @@
 {
 public:
   /**
-   * \brief Exception of UnixStreamFactory
-   */
-  class Error : public ProtocolFactory::Error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : ProtocolFactory::Error(what)
-    {
-    }
-  };
-
-  /**
    * \brief Create stream-oriented Unix channel using specified socket path
    *
    * If this method is called twice with the same path, only one channel
@@ -56,8 +43,6 @@
    *
    * \returns always a valid pointer to a UnixStreamChannel object,
    *          an exception will be thrown if the channel cannot be created.
-   *
-   * \throws UnixStreamFactory::Error
    */
   shared_ptr<UnixStreamChannel>
   createChannel(const std::string& unixSocketPath);
@@ -66,8 +51,9 @@
   virtual void
   createFace(const FaceUri& uri,
              ndn::nfd::FacePersistency persistency,
+             bool wantLocalFieldsEnabled,
              const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onConnectFailed) override;
+             const FaceCreationFailedCallback& onFailure) override;
 
   virtual std::vector<shared_ptr<const Channel>>
   getChannels() const override;
diff --git a/daemon/face/websocket-factory.cpp b/daemon/face/websocket-factory.cpp
index cea0078..a92d93e 100644
--- a/daemon/face/websocket-factory.cpp
+++ b/daemon/face/websocket-factory.cpp
@@ -53,10 +53,11 @@
 void
 WebSocketFactory::createFace(const FaceUri& uri,
                              ndn::nfd::FacePersistency persistency,
+                             bool wantLocalFieldsEnabled,
                              const FaceCreatedCallback& onCreated,
-                             const FaceCreationFailedCallback& onConnectFailed)
+                             const FaceCreationFailedCallback& onFailure)
 {
-  onConnectFailed(406, "Unsupported protocol");
+  onFailure(406, "Unsupported protocol");
 }
 
 std::vector<shared_ptr<const Channel>>
diff --git a/daemon/face/websocket-factory.hpp b/daemon/face/websocket-factory.hpp
index 110c026..1f784b7 100644
--- a/daemon/face/websocket-factory.hpp
+++ b/daemon/face/websocket-factory.hpp
@@ -35,19 +35,6 @@
 {
 public:
   /**
-   * \brief Exception of WebSocketFactory
-   */
-  class Error : public ProtocolFactory::Error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : ProtocolFactory::Error(what)
-    {
-    }
-  };
-
-  /**
    * \brief Create WebSocket-based channel using websocket::Endpoint
    *
    * websocket::Endpoint is really an alias for boost::asio::ip::tcp::endpoint.
@@ -58,8 +45,6 @@
    *
    * \returns always a valid pointer to a WebSocketChannel object, an exception
    *          is thrown if it cannot be created.
-   *
-   * \throws WebSocketFactory::Error
    */
   shared_ptr<WebSocketChannel>
   createChannel(const websocket::Endpoint& localEndpoint);
@@ -69,8 +54,6 @@
    *
    * This method is just a helper that converts a string representation of localIp and port to
    * websocket::Endpoint and calls the other createChannel overload.
-   *
-   * \throws WebSocketFactory::Error
    */
   shared_ptr<WebSocketChannel>
   createChannel(const std::string& localIp, const std::string& localPort);
@@ -79,8 +62,9 @@
   virtual void
   createFace(const FaceUri& uri,
              ndn::nfd::FacePersistency persistency,
+             bool wantLocalFieldsEnabled,
              const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onConnectFailed) override;
+             const FaceCreationFailedCallback& onFailure) override;
 
   virtual std::vector<shared_ptr<const Channel>>
   getChannels() const override;
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 783d21a..9078bca 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -115,6 +115,8 @@
   try {
     factory->second->createFace(uri,
                                 parameters.getFacePersistency(),
+                                parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) ?
+                                  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) : false,
                                 bind(&FaceManager::afterCreateFaceSuccess,
                                      this, parameters, _1, done),
                                 bind(&FaceManager::afterCreateFaceFailure,
@@ -140,20 +142,45 @@
  */
 void
 FaceManager::afterCreateFaceSuccess(const ControlParameters& parameters,
-                                    const shared_ptr<Face>& newFace,
+                                    const shared_ptr<Face>& face,
                                     const ndn::mgmt::CommandContinuation& done)
 {
+  // TODO: Re-enable check in #3232
+  //if (face->getId() != face::INVALID_FACEID) {
+  //// Face already exists
+  //ControlParameters response;
+  //response.setFaceId(face->getId());
+  //response.setUri(face->getRemoteUri().toString());
+  //response.setFacePersistency(face->getPersistency());
+  //
+  //auto linkService = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
+  //BOOST_ASSERT(linkService != nullptr);
+  //auto options = linkService->getOptions();
+  //response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false);
+  //
+  //  NFD_LOG_TRACE("Attempted to create duplicate face of " << face->getId());
+  //  done(ControlResponse(409, "Face with remote URI already exists").setBody(response.wireEncode()));
+  //}
+  //else {
+  // If scope non-local and flags set to enable local fields, request shouldn't
+  // have made it this far
+  BOOST_ASSERT(face->getScope() == ndn::nfd::FACE_SCOPE_LOCAL ||
+               !parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) ||
+               (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
+                !parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)));
+
+  m_faceTable.add(face);
+
   ControlParameters response;
-
-  m_faceTable.add(newFace);
-
-  // TODO: #3731: Verify and add Flags
-
-  // Set ControlResponse parameters
-  response.setFaceId(newFace->getId());
-  response.setFacePersistency(newFace->getPersistency());
+  response.setFaceId(face->getId());
+  response.setFacePersistency(face->getPersistency());
+  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
+                      parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) ?
+                        parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) : false,
+                      false);
 
   done(ControlResponse(200, "OK").setBody(response.wireEncode()));
+  //}
 }
 
 void
@@ -222,9 +249,13 @@
 
   setLinkServiceOptions(*face, parameters, response);
 
-  // Set remaining ControlResponse fields
+  // Set ControlResponse fields
   response.setFaceId(faceId);
   response.setFacePersistency(face->getPersistency());
+  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
+                      parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) ?
+                        parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) : false,
+                      false);
 
   done(ControlResponse(200, "OK").setBody(response.wireEncode()));
 }
diff --git a/tests/daemon/face/ethernet-factory.t.cpp b/tests/daemon/face/ethernet-factory.t.cpp
index b9e9cda..248a668 100644
--- a/tests/daemon/face/ethernet-factory.t.cpp
+++ b/tests/daemon/face/ethernet-factory.t.cpp
@@ -69,16 +69,19 @@
   createFace(factory,
              FaceUri("ether://[08:00:27:01:01:01]"),
              ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406, "Unsupported protocol"});
 
   createFace(factory,
              FaceUri("ether://[08:00:27:01:01:01]"),
              ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406, "Unsupported protocol"});
 
   createFace(factory,
              FaceUri("ether://[08:00:27:01:01:01]"),
              ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406, "Unsupported protocol"});
 }
 
diff --git a/tests/daemon/face/factory-test-common.hpp b/tests/daemon/face/factory-test-common.hpp
index 8676be5..e842ced 100644
--- a/tests/daemon/face/factory-test-common.hpp
+++ b/tests/daemon/face/factory-test-common.hpp
@@ -44,9 +44,10 @@
 createFace(ProtocolFactory& factory,
            const FaceUri& uri,
            ndn::nfd::FacePersistency persistency,
+           bool wantLocalFieldsEnabled,
            const CreateFaceExpectedResult& expected)
 {
-  factory.createFace(uri, persistency,
+  factory.createFace(uri, persistency, wantLocalFieldsEnabled,
                      [expected] (const shared_ptr<Face>& newFace) {
                        BOOST_CHECK_EQUAL(CreateFaceExpectedResult::SUCCESS, expected.result);
                      },
diff --git a/tests/daemon/face/tcp-channel.t.cpp b/tests/daemon/face/tcp-channel.t.cpp
index d04ea26..f8dae5d 100644
--- a/tests/daemon/face/tcp-channel.t.cpp
+++ b/tests/daemon/face/tcp-channel.t.cpp
@@ -77,7 +77,7 @@
   void
   connect(TcpChannel& channel)
   {
-    channel.connect(listenerEp,
+    channel.connect(listenerEp, false,
       [this] (const shared_ptr<Face>& newFace) {
         BOOST_REQUIRE(newFace != nullptr);
         connectFaceClosedSignal(*newFace, [this] { limitedIo.afterOp(); });
@@ -177,7 +177,7 @@
   // do not listen
 
   auto channel = makeChannel(A());
-  channel->connect(tcp::Endpoint(address, 7040),
+  channel->connect(tcp::Endpoint(address, 7040), false,
     [this] (const shared_ptr<Face>&) {
       BOOST_FAIL("Connect succeeded when it should have failed");
       this->limitedIo.afterOp();
diff --git a/tests/daemon/face/tcp-factory.t.cpp b/tests/daemon/face/tcp-factory.t.cpp
index 7418b26..a617011 100644
--- a/tests/daemon/face/tcp-factory.t.cpp
+++ b/tests/daemon/face/tcp-factory.t.cpp
@@ -79,6 +79,7 @@
   createFace(factory,
              FaceUri("tcp4://127.0.0.1:6363"),
              ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+             false,
              {CreateFaceExpectedResult::FAILURE, 504, "No channels available to connect"});
 
   factory.createChannel("127.0.0.1", "20071");
@@ -86,6 +87,7 @@
   createFace(factory,
              FaceUri("tcp4://127.0.0.1:20070"),
              ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+             false,
              {CreateFaceExpectedResult::SUCCESS, 0, ""});
 }
 
@@ -99,12 +101,14 @@
   createFace(factory,
              FaceUri("tcp4://127.0.0.1:20070"),
              ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406,
                "Outgoing TCP faces only support persistent persistency"});
 
   createFace(factory,
              FaceUri("tcp4://127.0.0.1:20071"),
              ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406,
                "Outgoing TCP faces only support persistent persistency"});
 }
@@ -143,6 +147,7 @@
 
   factory.createFace(FaceUri("tcp4://192.0.2.1:20070"),
                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                     false,
                      bind(&FaceCreateTimeoutFixture::onFaceCreated, this, _1),
                      bind(&FaceCreateTimeoutFixture::onConnectFailed, this, _2));
 
diff --git a/tests/daemon/face/udp-factory.t.cpp b/tests/daemon/face/udp-factory.t.cpp
index eb27f3a..5e46d97 100644
--- a/tests/daemon/face/udp-factory.t.cpp
+++ b/tests/daemon/face/udp-factory.t.cpp
@@ -151,6 +151,7 @@
   createFace(factory,
              FaceUri("udp4://127.0.0.1:6363"),
              ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+             false,
              {CreateFaceExpectedResult::FAILURE, 504, "No channels available to connect"});
 
   factory.createChannel("127.0.0.1", "20071");
@@ -158,16 +159,19 @@
   createFace(factory,
              FaceUri("udp4://127.0.0.1:20070"),
              ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+             false,
              {CreateFaceExpectedResult::SUCCESS, 0, ""});
   //test the upgrade
   createFace(factory,
              FaceUri("udp4://127.0.0.1:20070"),
              ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+             false,
              {CreateFaceExpectedResult::SUCCESS, 0, ""});
 
   createFace(factory,
              FaceUri("udp4://127.0.0.1:20072"),
              ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+             false,
              {CreateFaceExpectedResult::SUCCESS, 0, ""});
 }
 
@@ -180,6 +184,7 @@
   createFace(factory,
              FaceUri("udp4://127.0.0.1:20070"),
              ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406,
                "Outgoing unicast UDP faces do not support on-demand persistency"});
 }
diff --git a/tests/daemon/face/unix-stream-factory.t.cpp b/tests/daemon/face/unix-stream-factory.t.cpp
index 1c33122..832841f 100644
--- a/tests/daemon/face/unix-stream-factory.t.cpp
+++ b/tests/daemon/face/unix-stream-factory.t.cpp
@@ -80,16 +80,19 @@
   createFace(factory,
              FaceUri("unix:///var/run/nfd.sock"),
              ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406, "Unsupported protocol"});
 
   createFace(factory,
              FaceUri("unix:///var/run/nfd.sock"),
              ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406, "Unsupported protocol"});
 
   createFace(factory,
              FaceUri("unix:///var/run/nfd.sock"),
              ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406, "Unsupported protocol"});
 }
 
diff --git a/tests/daemon/face/websocket-factory.t.cpp b/tests/daemon/face/websocket-factory.t.cpp
index cb00922..e7abef2 100644
--- a/tests/daemon/face/websocket-factory.t.cpp
+++ b/tests/daemon/face/websocket-factory.t.cpp
@@ -62,16 +62,19 @@
   createFace(factory,
              FaceUri("ws://127.0.0.1:20070"),
              ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406, "Unsupported protocol"});
 
   createFace(factory,
              FaceUri("ws://127.0.0.1:20070"),
              ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406, "Unsupported protocol"});
 
   createFace(factory,
              FaceUri("ws://127.0.0.1:20070"),
              ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+             false,
              {CreateFaceExpectedResult::FAILURE, 406, "Unsupported protocol"});
 }
 
diff --git a/tests/daemon/mgmt/face-manager-create-face.t.cpp b/tests/daemon/mgmt/face-manager-create-face.t.cpp
index c691491..ed89388 100644
--- a/tests/daemon/mgmt/face-manager-create-face.t.cpp
+++ b/tests/daemon/mgmt/face-manager-create-face.t.cpp
@@ -120,6 +120,58 @@
   }
 };
 
+class LocalTcpFaceLocalFieldsEnabled
+{
+public:
+  ControlParameters
+  getParameters()
+  {
+    return ControlParameters()
+      .setUri("tcp4://127.0.0.1:26363")
+      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
+      .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, true);
+  }
+};
+
+class LocalTcpFaceLocalFieldsDisabled
+{
+public:
+  ControlParameters
+  getParameters()
+  {
+    return ControlParameters()
+      .setUri("tcp4://127.0.0.1:26363")
+      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
+      .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, false);
+  }
+};
+
+class NonLocalUdpFaceLocalFieldsEnabled // won't work because non-local scope
+{
+public:
+  ControlParameters
+  getParameters()
+  {
+    return ControlParameters()
+      .setUri("udp4://127.0.0.1:26363")
+      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
+      .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, true);
+  }
+};
+
+class NonLocalUdpFaceLocalFieldsDisabled
+{
+public:
+  ControlParameters
+  getParameters()
+  {
+    return ControlParameters()
+      .setUri("udp4://127.0.0.1:26363")
+      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
+      .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, false);
+  }
+};
+
 namespace mpl = boost::mpl;
 
 // pairs of CreateCommand and Success/Failure status
@@ -129,7 +181,11 @@
                     mpl::pair<UdpFaceOnDemand, CommandFailure<406>>,
                     mpl::pair<UdpFacePersistent, CommandSuccess>,
                     mpl::pair<UdpFacePermanent, CommandSuccess>,
-                    mpl::pair<UdpFaceConnectToSelf, CommandFailure<406>>> Faces;
+                    mpl::pair<UdpFaceConnectToSelf, CommandFailure<406>>,
+                    mpl::pair<LocalTcpFaceLocalFieldsEnabled, CommandSuccess>,
+                    mpl::pair<LocalTcpFaceLocalFieldsDisabled, CommandSuccess>,
+                    mpl::pair<NonLocalUdpFaceLocalFieldsEnabled, CommandFailure<406>>,
+                    mpl::pair<NonLocalUdpFaceLocalFieldsDisabled, CommandSuccess>> Faces;
 
 BOOST_FIXTURE_TEST_CASE_TEMPLATE(NewFace, T, Faces, FaceManagerCommandFixture)
 {
@@ -162,10 +218,12 @@
 
       if (actual.getCode() == 200) {
         if (expectedParams.hasFlags()) {
-          // TODO: #3731 check if Flags match
+          BOOST_CHECK_EQUAL(expectedParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED),
+                            actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
         }
         else {
-          // TODO: #3731 check if Flags at defaults
+          // local fields are disabled by default
+          BOOST_CHECK_EQUAL(actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED), false);
         }
       }
       else {
@@ -193,7 +251,7 @@
 
 
 typedef mpl::vector<// mpl::pair<mpl::pair<TcpFacePersistent, TcpFacePermanent>, TcpFacePermanent>, // no need to check now
-                    // mpl::pair<mpl::pair<TcpFacePermanent, TcpFacePersistent>, TcpFacePermanent>, // no need to check now
+                    // mpl::pair<mpl::pair<TcpFacePermanent, TcpFacePersistent>, TcpFacePersistent>, // no need to check now
                     mpl::pair<mpl::pair<UdpFacePersistent, UdpFacePermanent>, UdpFacePermanent>,
                     mpl::pair<mpl::pair<UdpFacePermanent, UdpFacePersistent>, UdpFacePermanent>> FaceTransitions;
 
@@ -235,6 +293,7 @@
 
         ControlResponse actual(response.getContent().blockFromValue());
         BOOST_REQUIRE_EQUAL(actual.getCode(), 200);
+        BOOST_TEST_MESSAGE(actual.getText());
 
         ControlParameters expectedParams(FinalFaceType().getParameters());
         ControlParameters actualParams(actual.getBody());
diff --git a/tests/daemon/mgmt/face-manager.t.cpp b/tests/daemon/mgmt/face-manager.t.cpp
index 3c34cb2..9b7c71a 100644
--- a/tests/daemon/mgmt/face-manager.t.cpp
+++ b/tests/daemon/mgmt/face-manager.t.cpp
@@ -335,6 +335,7 @@
   virtual void
   createFace(const FaceUri& uri,
              ndn::nfd::FacePersistency persistency,
+             bool wantLocalFieldsEnabled,
              const FaceCreatedCallback& onCreated,
              const FaceCreationFailedCallback& onConnectFailed) override
   {
diff --git a/tests/other/face-benchmark.cpp b/tests/other/face-benchmark.cpp
index c468bf1..7017a7d 100644
--- a/tests/other/face-benchmark.cpp
+++ b/tests/other/face-benchmark.cpp
@@ -128,6 +128,7 @@
     auto port = boost::lexical_cast<uint16_t>(uriR.getPort());
     if (uriR.getScheme() == "tcp4") {
       m_tcpChannel.connect(tcp::Endpoint(addr, port),
+                           false,
                            bind(&FaceBenchmark::onRightFaceCreated, this, faceL, _1),
                            bind(&FaceBenchmark::onFaceCreationFailed, _1, _2));
     }