mgmt: LpFace faces/enable-local-control workaround

In this temporary workaround,
faces/enable-local-control enables all local fields in GenericLinkService,
and faces/disable-local-control disables all local fields in GenericLinkService.

This commit also modifies FaceTable::remove to retain shared_ptr<Face>
until signal execution is complete.

refs #3226

Change-Id: I3513e97ec2af87df94dbf57a7256b895ed9d2103
diff --git a/daemon/fw/face-table.cpp b/daemon/fw/face-table.cpp
index 1884203..a8a8053 100644
--- a/daemon/fw/face-table.cpp
+++ b/daemon/fw/face-table.cpp
@@ -25,6 +25,7 @@
 
 #include "face-table.hpp"
 #include "forwarder.hpp"
+#include "core/global-io.hpp"
 #include "core/logger.hpp"
 
 namespace nfd {
@@ -111,6 +112,9 @@
                " (" << reason << ")");
 
   m_forwarder.getFib().removeNextHopFromAllEntries(face);
+
+  // defer Face deallocation, so that Transport isn't deallocated during afterStateChange signal
+  getGlobalIoService().post([face] {});
 }
 
 FaceTable::ForwardRange
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index b49b752..29cac39 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -26,6 +26,7 @@
 #include "face-manager.hpp"
 
 #include "core/network-interface.hpp"
+#include "face/generic-link-service.hpp"
 #include "face/lp-face-wrapper.hpp"
 #include "face/tcp-factory.hpp"
 #include "face/udp-factory.hpp"
@@ -133,43 +134,6 @@
 }
 
 void
-FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
-                         const ControlParameters& parameters,
-                         const ndn::mgmt::CommandContinuation& done)
-{
-  shared_ptr<Face> target = m_faceTable.get(parameters.getFaceId());
-  if (target) {
-    target->close();
-  }
-
-  done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
-}
-
-void
-FaceManager::enableLocalControl(const Name& topPrefix, const Interest& interest,
-                                const ControlParameters& parameters,
-                                const ndn::mgmt::CommandContinuation& done)
-{
-  auto result = extractLocalControlParameters(interest, parameters, done);
-  if (result.isValid) {
-    result.face->setLocalControlHeaderFeature(result.feature, true);
-    return done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
-  }
-}
-
-void
-FaceManager::disableLocalControl(const Name& topPrefix, const Interest& interest,
-                                 const ControlParameters& parameters,
-                                 const ndn::mgmt::CommandContinuation& done)
-{
-  auto result = extractLocalControlParameters(interest, parameters, done);
-  if (result.isValid) {
-    result.face->setLocalControlHeaderFeature(result.feature, false);
-    return done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
-  }
-}
-
-void
 FaceManager::afterCreateFaceSuccess(ControlParameters& parameters,
                                     const shared_ptr<Face>& newFace,
                                     const ndn::mgmt::CommandContinuation& done)
@@ -183,6 +147,19 @@
 }
 
 void
+FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
+                         const ControlParameters& parameters,
+                         const ndn::mgmt::CommandContinuation& done)
+{
+  shared_ptr<Face> target = m_faceTable.get(parameters.getFaceId());
+  if (target) {
+    target->close();
+  }
+
+  done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
+}
+
+void
 FaceManager::afterCreateFaceFailure(const std::string& reason,
                                     const ndn::mgmt::CommandContinuation& done)
 {
@@ -191,6 +168,68 @@
   done(ControlResponse(408, "Failed to create face: " + reason));
 }
 
+void
+FaceManager::enableLocalControl(const Name& topPrefix, const Interest& interest,
+                                const ControlParameters& parameters,
+                                const ndn::mgmt::CommandContinuation& done)
+{
+  auto result = extractLocalControlParameters(interest, parameters, done);
+  if (!result.isValid) {
+    return;
+  }
+
+  if (result.face) {
+    result.face->setLocalControlHeaderFeature(result.feature, true);
+    return done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
+  }
+
+  // TODO#3226 redesign enable-local-control
+  // For now, enable-local-control will enable all local fields in GenericLinkService.
+  BOOST_ASSERT(result.lpFace != nullptr);
+  auto service = dynamic_cast<face::GenericLinkService*>(result.lpFace->getLinkService());
+  if (service == nullptr) {
+    return done(ControlResponse(503, "LinkService type not supported"));
+  }
+
+  face::GenericLinkService::Options options = service->getOptions();
+  options.allowLocalFields = true;
+  service->setOptions(options);
+
+  return done(ControlResponse(200, "OK: enable all local fields on GenericLinkService")
+              .setBody(parameters.wireEncode()));
+}
+
+void
+FaceManager::disableLocalControl(const Name& topPrefix, const Interest& interest,
+                                 const ControlParameters& parameters,
+                                 const ndn::mgmt::CommandContinuation& done)
+{
+  auto result = extractLocalControlParameters(interest, parameters, done);
+  if (!result.isValid) {
+    return;
+  }
+
+  if (result.face) {
+    result.face->setLocalControlHeaderFeature(result.feature, false);
+    return done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
+  }
+
+  // TODO#3226 redesign disable-local-control
+  // For now, disable-local-control will disable all local fields in GenericLinkService.
+  BOOST_ASSERT(result.lpFace != nullptr);
+  auto service = dynamic_cast<face::GenericLinkService*>(result.lpFace->getLinkService());
+  if (service == nullptr) {
+    return done(ControlResponse(503, "LinkService type not supported"));
+  }
+
+  face::GenericLinkService::Options options = service->getOptions();
+  options.allowLocalFields = false;
+  service->setOptions(options);
+
+  return done(ControlResponse(200, "OK: disable all local fields on GenericLinkService")
+              .setBody(parameters.wireEncode()));
+}
+
 FaceManager::ExtractLocalControlParametersResult
 FaceManager::extractLocalControlParameters(const Interest& request,
                                            const ControlParameters& parameters,
@@ -198,6 +237,7 @@
 {
   ExtractLocalControlParametersResult result;
   result.isValid = false;
+  result.lpFace = nullptr;
 
   auto face = m_faceTable.get(request.getIncomingFaceId());
   if (!static_cast<bool>(face)) {
@@ -215,6 +255,11 @@
 
   result.isValid = true;
   result.face = dynamic_pointer_cast<LocalFace>(face);
+  if (result.face == nullptr) {
+    auto lpFaceW = dynamic_pointer_cast<face::LpFaceWrapper>(face);
+    BOOST_ASSERT(lpFaceW != nullptr);
+    result.lpFace = lpFaceW->getLpFace();
+  }
   result.feature = static_cast<LocalControlFeature>(parameters.getLocalControlFeature());
 
   return result;
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index f5283d6..e3c955f 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -36,6 +36,10 @@
 class NetworkInterfaceInfo;
 class ProtocolFactory;
 
+namespace face {
+class LpFace;
+} // namespace face
+
 /**
  * @brief implement the Face Management of NFD Management Protocol.
  * @sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt
@@ -88,6 +92,7 @@
   {
     bool isValid;
     shared_ptr<LocalFace> face;
+    face::LpFace* lpFace;
     LocalControlFeature feature;
   };