mgmt, main: add strategy choice management and deprecate fib/set-strategy

refs: #1311

Change-Id: Icc88f201f3c13a5a25ec1bdadec35f93c76b2b94
diff --git a/daemon/mgmt/strategy-choice-manager.cpp b/daemon/mgmt/strategy-choice-manager.cpp
new file mode 100644
index 0000000..00761dd
--- /dev/null
+++ b/daemon/mgmt/strategy-choice-manager.cpp
@@ -0,0 +1,169 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "strategy-choice-manager.hpp"
+#include "table/strategy-choice.hpp"
+#include "mgmt/app-face.hpp"
+
+namespace nfd {
+
+NFD_LOG_INIT("StrategyChoiceManager");
+
+const Name StrategyChoiceManager::COMMAND_PREFIX = "/localhost/nfd/strategy-choice";
+
+const size_t StrategyChoiceManager::COMMAND_UNSIGNED_NCOMPS =
+  StrategyChoiceManager::COMMAND_PREFIX.size() +
+  1 + // verb
+  1;  // verb options
+
+const size_t StrategyChoiceManager::COMMAND_SIGNED_NCOMPS =
+  StrategyChoiceManager::COMMAND_UNSIGNED_NCOMPS +
+  0; // No signed Interest support in mock, otherwise 4 (timestamp, nonce, signed info tlv, signature tlv)
+
+StrategyChoiceManager::StrategyChoiceManager(StrategyChoice& strategyChoice,
+                                             shared_ptr<AppFace> face)
+  : ManagerBase(face)
+  , m_strategyChoice(strategyChoice)
+{
+  face->setInterestFilter("/localhost/nfd/strategy-choice",
+                          bind(&StrategyChoiceManager::onStrategyChoiceRequest, this, _2));
+}
+
+StrategyChoiceManager::~StrategyChoiceManager()
+{
+
+}
+
+void
+StrategyChoiceManager::onStrategyChoiceRequest(const Interest& request)
+{
+  const Name& command = request.getName();
+  const size_t commandNComps = command.size();
+
+  if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
+      commandNComps < COMMAND_SIGNED_NCOMPS)
+    {
+      NFD_LOG_INFO("command result: unsigned verb: " << command);
+      sendResponse(command, 401, "Signature required");
+
+      return;
+    }
+  else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
+           !COMMAND_PREFIX.isPrefixOf(command))
+    {
+      NFD_LOG_INFO("command result: malformed");
+      sendResponse(command, 400, "Malformed command");
+      return;
+    }
+
+  onValidatedStrategyChoiceRequest(request.shared_from_this());
+}
+
+void
+StrategyChoiceManager::onValidatedStrategyChoiceRequest(const shared_ptr<const Interest>& request)
+{
+  static const Name::Component VERB_SET("set");
+  static const Name::Component VERB_UNSET("unset");
+
+  const Name& command = request->getName();
+
+  ndn::nfd::FibManagementOptions options;
+  if (!extractOptions(*request, options))
+    {
+      sendResponse(command, 400, "Malformed command");
+      return;
+    }
+
+  const Name::Component& verb = command.get(COMMAND_PREFIX.size());
+  ControlResponse response;
+  if (verb == VERB_SET)
+    {
+      setStrategy(options, response);
+    }
+  else if (verb == VERB_UNSET)
+    {
+      unsetStrategy(options, response);
+    }
+  else
+    {
+      NFD_LOG_INFO("command result: unsupported verb: " << verb);
+      setResponse(response, 501, "Unsupported command");
+    }
+  sendResponse(command, response);
+}
+
+bool
+StrategyChoiceManager::extractOptions(const Interest& request,
+                                      ndn::nfd::FibManagementOptions& extractedOptions)
+{
+  const Name& command = request.getName();
+  const size_t optionCompIndex =
+    COMMAND_PREFIX.size() + 1;
+
+  try
+    {
+      Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
+      extractedOptions.wireDecode(rawOptions);
+    }
+  catch (const ndn::Tlv::Error& e)
+    {
+      NFD_LOG_INFO("Bad command option parse: " << command);
+      return false;
+    }
+
+  NFD_LOG_DEBUG("Options parsed OK");
+  return true;
+}
+
+void
+StrategyChoiceManager::setStrategy(const ndn::nfd::FibManagementOptions& options,
+                                   ControlResponse& response)
+{
+  const Name& prefix = options.getName();
+  const Name& selectedStrategy = options.getStrategy();
+
+  if (!m_strategyChoice.hasStrategy(selectedStrategy))
+    {
+      NFD_LOG_INFO("strategy-choice result: FAIL reason: unknown-strategy: "
+                   << options.getStrategy());
+      setResponse(response, 504, "Unsupported strategy");
+      return;
+    }
+
+  if (m_strategyChoice.insert(prefix, selectedStrategy))
+    {
+      setResponse(response, 200, "Success", options.wireEncode());
+    }
+  else
+    {
+      setResponse(response, 405, "Strategy not installed");
+    }
+}
+
+void
+StrategyChoiceManager::unsetStrategy(const ndn::nfd::FibManagementOptions& options,
+                                     ControlResponse& response)
+{
+  static const Name ROOT_PREFIX;
+
+  const Name& prefix = options.getName();
+  if (prefix == ROOT_PREFIX)
+    {
+      NFD_LOG_INFO("strategy-choice result: FAIL reason: unknown-prefix: "
+                   << options.getName());
+      setResponse(response, 403, "Cannot unset root prefix strategy");
+      return;
+    }
+
+  m_strategyChoice.erase(prefix);
+  setResponse(response, 200, "Success", options.wireEncode());
+}
+
+
+
+} // namespace nfd
+
+