mgmt: add faces/update command

refs #3731

Change-Id: I79777a10feecb2de83276371100cc86a43d0e76d
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 9cd0e07..f41f4de 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -59,6 +59,9 @@
   registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
     bind(&FaceManager::createFace, this, _2, _3, _4, _5));
 
+  registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update",
+    bind(&FaceManager::updateFace, this, _2, _3, _4, _5));
+
   registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
     bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
 
@@ -143,6 +146,8 @@
 
   m_faceTable.add(newFace);
 
+  // TODO: #3731: Verify and add Flags
+
   // Set ControlResponse parameters
   response.setFaceId(newFace->getId());
   response.setFacePersistency(newFace->getPersistency());
@@ -161,6 +166,69 @@
 }
 
 void
+FaceManager::updateFace(const Name& topPrefix, const Interest& interest,
+                        const ControlParameters& parameters,
+                        const ndn::mgmt::CommandContinuation& done)
+{
+  FaceId faceId = parameters.getFaceId();
+  if (faceId == 0) {
+    // Self-updating
+    shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = interest.getTag<lp::IncomingFaceIdTag>();
+    if (incomingFaceIdTag == nullptr) {
+      NFD_LOG_TRACE("unable to determine face for self-update");
+      done(ControlResponse(404, "No FaceId specified and IncomingFaceId not available"));
+      return;
+    }
+    faceId = *incomingFaceIdTag;
+  }
+
+  Face* face = m_faceTable.get(faceId);
+
+  if (face == nullptr) {
+    NFD_LOG_TRACE("invalid face specified");
+    done(ControlResponse(404, "Specified face does not exist"));
+    return;
+  }
+
+  // Verify validity of requested changes
+  ControlParameters response;
+  bool areParamsValid = true;
+
+  if (parameters.hasFacePersistency()) {
+    // TODO #3232: Add FacePersistency updating
+    NFD_LOG_TRACE("received unsupported face persistency change");
+    areParamsValid = false;
+    response.setFacePersistency(parameters.getFacePersistency());
+  }
+
+  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
+      parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
+      face->getScope() != ndn::nfd::FACE_SCOPE_LOCAL) {
+    NFD_LOG_TRACE("received request to enable local fields on non-local face");
+    areParamsValid = false;
+    response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
+                        parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
+  }
+
+  if (!areParamsValid) {
+    done(ControlResponse(409, "Invalid properties specified").setBody(response.wireEncode()));
+    return;
+  }
+
+  // All specified properties are valid, so make changes
+
+  // TODO #3232: Add FacePersistency updating
+
+  setLinkServiceOptions(*face, parameters, response);
+
+  // Set remaining ControlResponse fields
+  response.setFaceId(faceId);
+  response.setFacePersistency(face->getPersistency());
+
+  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
+}
+
+void
 FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
                          const ControlParameters& parameters,
                          const ndn::mgmt::CommandContinuation& done)
@@ -183,8 +251,7 @@
     return;
   }
 
-  // TODO#3226 redesign enable-local-control
-  // For now, enable-local-control will enable all local fields in GenericLinkService.
+  // enable-local-control will enable all local fields in GenericLinkService
   auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
   if (service == nullptr) {
     return done(ControlResponse(503, "LinkService type not supported"));
@@ -208,8 +275,7 @@
     return;
   }
 
-  // TODO#3226 redesign disable-local-control
-  // For now, disable-local-control will disable all local fields in GenericLinkService.
+  // disable-local-control will disable all local fields in GenericLinkService
   auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
   if (service == nullptr) {
     return done(ControlResponse(503, "LinkService type not supported"));
@@ -251,6 +317,25 @@
 }
 
 void
+FaceManager::setLinkServiceOptions(Face& face,
+                                   const ControlParameters& parameters,
+                                   ControlParameters& response)
+{
+  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
+  BOOST_ASSERT(linkService != nullptr);
+
+  auto options = linkService->getOptions();
+  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
+      face.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
+    options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
+  }
+  linkService->setOptions(options);
+
+  // Set Flags for ControlResponse
+  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false);
+}
+
+void
 FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
                        ndn::mgmt::StatusDatasetContext& context)
 {
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index 094f288..b168da4 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -61,15 +61,26 @@
              const ndn::mgmt::CommandContinuation& done);
 
   void
+  updateFace(const Name& topPrefix, const Interest& interest,
+             const ControlParameters& parameters,
+             const ndn::mgmt::CommandContinuation& done);
+
+  void
   destroyFace(const Name& topPrefix, const Interest& interest,
               const ControlParameters& parameters,
               const ndn::mgmt::CommandContinuation& done);
 
+  /**
+   * \deprecated use Flags+Mask in faces/update instead
+   */
   void
   enableLocalControl(const Name& topPrefix, const Interest& interest,
                      const ControlParameters& parameters,
                      const ndn::mgmt::CommandContinuation& done);
 
+  /**
+   * \deprecated use Flags+Mask in faces/update instead
+   */
   void
   disableLocalControl(const Name& topPrefix, const Interest& interest,
                       const ControlParameters& parameters,
@@ -91,6 +102,11 @@
                           const ControlParameters& parameters,
                           const ndn::mgmt::CommandContinuation& done);
 
+  static void
+  setLinkServiceOptions(Face& face,
+                        const ControlParameters& parameters,
+                        ControlParameters& response);
+
 PUBLIC_WITH_TESTS_ELSE_PRIVATE: // StatusDataset
   void
   listFaces(const Name& topPrefix, const Interest& interest,
@@ -151,9 +167,9 @@
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   std::map<std::string /*protocol*/, shared_ptr<ProtocolFactory>> m_factories;
+  FaceTable& m_faceTable;
 
 private:
-  FaceTable& m_faceTable;
   ndn::mgmt::PostNotification m_postNotification;
   signal::ScopedConnection m_faceAddConn;
   signal::ScopedConnection m_faceRemoveConn;