tools: split nfdc into multiple files

refs #3749

Change-Id: I24a3fd287773d0577d438e9ca24dc1dfab335a4f
diff --git a/tools/nfdc.cpp b/tools/nfdc.cpp
deleted file mode 100644
index 31ce4f3..0000000
--- a/tools/nfdc.cpp
+++ /dev/null
@@ -1,627 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2016,  Regents of the University of California,
- *                           Arizona Board of Regents,
- *                           Colorado State University,
- *                           University Pierre & Marie Curie, Sorbonne University,
- *                           Washington University in St. Louis,
- *                           Beijing Institute of Technology,
- *                           The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "nfdc.hpp"
-#include "core/version.hpp"
-
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/regex_find_format.hpp>
-#include <boost/regex.hpp>
-
-#include <ndn-cxx/management/nfd-face-query-filter.hpp>
-#include <ndn-cxx/management/nfd-face-status.hpp>
-#include <ndn-cxx/util/segment-fetcher.hpp>
-
-void
-usage(const char* programName)
-{
-  std::cout << "Usage:\n" << programName  << " [-h] [-V] COMMAND [<Command Options>]\n"
-    "       -h print usage and exit\n"
-    "       -V print version and exit\n"
-    "\n"
-    "   COMMAND can be one of the following:\n"
-    "       register [-I] [-C] [-c cost] [-e expiration time] [-o origin] name <faceId | faceUri>\n"
-    "           register name to the given faceId or faceUri\n"
-    "           -I: unset CHILD_INHERIT flag\n"
-    "           -C: set CAPTURE flag\n"
-    "           -c: specify cost (default 0)\n"
-    "           -e: specify expiration time in ms\n"
-    "               (by default the entry remains in FIB for the lifetime of the associated face)\n"
-    "           -o: specify origin\n"
-    "               0 for Local producer applications, 128 for NLSR, 255(default) for static routes\n"
-    "       unregister [-o origin] name <faceId | faceUri>\n"
-    "           unregister name from the given faceId\n"
-    "       create [-P] <faceUri> \n"
-    "           Create a face in one of the following formats:\n"
-    "           UDP unicast:    udp[4|6]://<remote-IP-or-host>[:<remote-port>]\n"
-    "           TCP:            tcp[4|6]://<remote-IP-or-host>[:<remote-port>] \n"
-    "           -P: create permanent (instead of persistent) face\n"
-    "       destroy <faceId | faceUri> \n"
-    "           Destroy a face\n"
-    "       set-strategy <name> <strategy> \n"
-    "           Set the strategy for a namespace \n"
-    "       unset-strategy <name> \n"
-    "           Unset the strategy for a namespace \n"
-    "       add-nexthop [-c <cost>] <name> <faceId | faceUri>\n"
-    "           Add a nexthop to a FIB entry\n"
-    "           -c: specify cost (default 0)\n"
-    "       remove-nexthop <name> <faceId | faceUri> \n"
-    "           Remove a nexthop from a FIB entry\n"
-    << std::endl;
-}
-
-namespace nfdc {
-
-using std::bind;
-
-const ndn::time::milliseconds Nfdc::DEFAULT_EXPIRATION_PERIOD = ndn::time::milliseconds::max();
-const uint64_t Nfdc::DEFAULT_COST = 0;
-
-Nfdc::FaceIdFetcher::FaceIdFetcher(ndn::Face& face,
-                                   Controller& controller,
-                                   bool allowCreate,
-                                   const SuccessCallback& onSucceed,
-                                   const FailureCallback& onFail)
-  : m_face(face)
-  , m_controller(controller)
-  , m_allowCreate(allowCreate)
-  , m_onSucceed(onSucceed)
-  , m_onFail(onFail)
-{
-}
-
-void
-Nfdc::FaceIdFetcher::start(ndn::Face& face,
-                           Controller& controller,
-                           const std::string& input,
-                           bool allowCreate,
-                           const SuccessCallback& onSucceed,
-                           const FailureCallback& onFail)
-{
-  // 1. Try parse input as FaceId, if input is FaceId, succeed with parsed FaceId
-  // 2. Try parse input as FaceUri, if input is not FaceUri, fail
-  // 3. Canonize faceUri
-  // 4. If canonization fails, fail
-  // 5. Query for face
-  // 6. If query succeeds and finds a face, succeed with found FaceId
-  // 7. Create face
-  // 8. If face creation succeeds, succeed with created FaceId
-  // 9. Fail
-
-  boost::regex e("^[a-z0-9]+\\:.*");
-  if (!boost::regex_match(input, e)) {
-    try
-      {
-        u_int32_t faceId = boost::lexical_cast<uint32_t>(input);
-        onSucceed(faceId);
-        return;
-      }
-    catch (boost::bad_lexical_cast&)
-      {
-        onFail("No valid faceId or faceUri is provided");
-        return;
-      }
-  }
-  else {
-    ndn::util::FaceUri faceUri;
-    if (!faceUri.parse(input)) {
-      onFail("FaceUri parse failed");
-      return;
-    }
-
-    auto fetcher = new FaceIdFetcher(std::ref(face), std::ref(controller),
-                                     allowCreate, onSucceed, onFail);
-
-    fetcher->startGetFaceId(faceUri);
-  }
-}
-
-void
-Nfdc::FaceIdFetcher::startGetFaceId(const ndn::util::FaceUri& faceUri)
-{
-  faceUri.canonize(bind(&FaceIdFetcher::onCanonizeSuccess, this, _1),
-                   bind(&FaceIdFetcher::onCanonizeFailure, this, _1),
-                   m_face.getIoService(), ndn::time::seconds(4));
-}
-
-void
-Nfdc::FaceIdFetcher::onCanonizeSuccess(const ndn::util::FaceUri& canonicalUri)
-{
-  ndn::Name queryName("/localhost/nfd/faces/query");
-  ndn::nfd::FaceQueryFilter queryFilter;
-  queryFilter.setRemoteUri(canonicalUri.toString());
-  queryName.append(queryFilter.wireEncode());
-
-  ndn::Interest interestPacket(queryName);
-  interestPacket.setMustBeFresh(true);
-  interestPacket.setInterestLifetime(ndn::time::milliseconds(4000));
-  auto interest = std::make_shared<ndn::Interest>(interestPacket);
-
-  ndn::util::SegmentFetcher::fetch(m_face, *interest,
-                                   m_validator,
-                                   bind(&FaceIdFetcher::onQuerySuccess,
-                                        this, _1, canonicalUri),
-                                   bind(&FaceIdFetcher::onQueryFailure,
-                                        this, _1, canonicalUri));
-}
-
-void
-Nfdc::FaceIdFetcher::onCanonizeFailure(const std::string& reason)
-{
-  fail("Canonize faceUri failed : " + reason);
-}
-
-void
-Nfdc::FaceIdFetcher::onQuerySuccess(const ndn::ConstBufferPtr& data,
-                                    const ndn::util::FaceUri& canonicalUri)
-{
-  size_t offset = 0;
-  bool isOk = false;
-  ndn::Block block;
-  std::tie(isOk, block) = ndn::Block::fromBuffer(data, offset);
-
-  if (!isOk) {
-    if (m_allowCreate) {
-      startFaceCreate(canonicalUri);
-    }
-    else {
-      fail("Fail to find faceId");
-    }
-  }
-  else {
-    try {
-      FaceStatus status(block);
-      succeed(status.getFaceId());
-    }
-    catch (const ndn::tlv::Error& e) {
-      std::string errorMessage(e.what());
-      fail("ERROR: " + errorMessage);
-    }
-  }
-}
-
-void
-Nfdc::FaceIdFetcher::onQueryFailure(uint32_t errorCode,
-                                    const ndn::util::FaceUri& canonicalUri)
-{
-  std::stringstream ss;
-  ss << "Cannot fetch data (code " << errorCode << ")";
-  fail(ss.str());
-}
-
-void
-Nfdc::FaceIdFetcher::onFaceCreateError(uint32_t code,
-                                       const std::string& error,
-                                       const std::string& message)
-{
-  std::stringstream ss;
-  ss << message << " : " << error << " (code " << code << ")";
-  fail(ss.str());
-}
-
-void
-Nfdc::FaceIdFetcher::startFaceCreate(const ndn::util::FaceUri& canonicalUri)
-{
-  ControlParameters parameters;
-  parameters.setUri(canonicalUri.toString());
-
-  m_controller.start<FaceCreateCommand>(parameters,
-                                        [this] (const ControlParameters& result) {
-                                          succeed(result.getFaceId());
-                                        },
-                                        bind(&FaceIdFetcher::onFaceCreateError, this, _1, _2,
-                                             "Face creation failed"));
-}
-
-void
-Nfdc::FaceIdFetcher::succeed(uint32_t faceId)
-{
-  m_onSucceed(faceId);
-  delete this;
-}
-
-void
-Nfdc::FaceIdFetcher::fail(const std::string& reason)
-{
-  m_onFail(reason);
-  delete this;
-}
-
-Nfdc::Nfdc(ndn::Face& face)
-  : m_flags(ROUTE_FLAG_CHILD_INHERIT)
-  , m_cost(DEFAULT_COST)
-  , m_origin(ROUTE_ORIGIN_STATIC)
-  , m_expires(DEFAULT_EXPIRATION_PERIOD)
-  , m_facePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT)
-  , m_face(face)
-  , m_controller(face, m_keyChain)
-  , m_ioService(face.getIoService())
-{
-}
-
-Nfdc::~Nfdc()
-{
-}
-
-bool
-Nfdc::dispatch(const std::string& command)
-{
-  if (command == "add-nexthop") {
-    if (m_nOptions != 2)
-      return false;
-    fibAddNextHop();
-  }
-  else if (command == "remove-nexthop") {
-    if (m_nOptions != 2)
-      return false;
-    fibRemoveNextHop();
-  }
-  else if (command == "register") {
-    if (m_nOptions != 2)
-      return false;
-    ribRegisterPrefix();
-  }
-  else if (command == "unregister") {
-    if (m_nOptions != 2)
-      return false;
-    ribUnregisterPrefix();
-  }
-  else if (command == "create") {
-    if (m_nOptions != 1)
-      return false;
-    faceCreate();
-  }
-  else if (command == "destroy") {
-    if (m_nOptions != 1)
-      return false;
-    faceDestroy();
-  }
-  else if (command == "set-strategy") {
-    if (m_nOptions != 2)
-      return false;
-    strategyChoiceSet();
-  }
-  else if (command == "unset-strategy") {
-    if (m_nOptions != 1)
-      return false;
-    strategyChoiceUnset();
-  }
-  else
-    return false;
-
-  return true;
-}
-
-void
-Nfdc::fibAddNextHop()
-{
-  m_name = m_commandLineArguments[0];
-  const std::string& faceName = m_commandLineArguments[1];
-
-  FaceIdFetcher::start(m_face, m_controller, faceName, true,
-                       [this] (const uint32_t faceId) {
-                         ControlParameters parameters;
-                         parameters
-                           .setName(m_name)
-                           .setCost(m_cost)
-                           .setFaceId(faceId);
-
-                         m_controller
-                           .start<FibAddNextHopCommand>(parameters,
-                                                        bind(&Nfdc::onSuccess, this, _1,
-                                                             "Nexthop insertion succeeded"),
-                                                        bind(&Nfdc::onError, this, _1, _2,
-                                                             "Nexthop insertion failed"));
-                       },
-                       bind(&Nfdc::onObtainFaceIdFailure, this, _1));
-}
-
-void
-Nfdc::fibRemoveNextHop()
-{
-  m_name = m_commandLineArguments[0];
-  const std::string& faceName = m_commandLineArguments[1];
-
-  FaceIdFetcher::start(m_face, m_controller, faceName, false,
-                       [this] (const uint32_t faceId) {
-                         ControlParameters parameters;
-                         parameters
-                           .setName(m_name)
-                           .setFaceId(faceId);
-
-                         m_controller
-                           .start<FibRemoveNextHopCommand>(parameters,
-                                                           bind(&Nfdc::onSuccess, this, _1,
-                                                                "Nexthop removal succeeded"),
-                                                           bind(&Nfdc::onError, this, _1, _2,
-                                                                "Nexthop removal failed"));
-                       },
-                       bind(&Nfdc::onObtainFaceIdFailure, this, _1));
-}
-
-void
-Nfdc::ribRegisterPrefix()
-{
-  m_name = m_commandLineArguments[0];
-  const std::string& faceName = m_commandLineArguments[1];
-
-  FaceIdFetcher::start(m_face, m_controller, faceName, true,
-                       [this] (const uint32_t faceId) {
-                         ControlParameters parameters;
-                         parameters
-                           .setName(m_name)
-                           .setCost(m_cost)
-                           .setFlags(m_flags)
-                           .setOrigin(m_origin)
-                           .setFaceId(faceId);
-
-                         if (m_expires != DEFAULT_EXPIRATION_PERIOD)
-                           parameters.setExpirationPeriod(m_expires);
-
-                         m_controller
-                           .start<RibRegisterCommand>(parameters,
-                                                      bind(&Nfdc::onSuccess, this, _1,
-                                                           "Successful in name registration"),
-                                                      bind(&Nfdc::onError, this, _1, _2,
-                                                           "Failed in name registration"));
-                       },
-                       bind(&Nfdc::onObtainFaceIdFailure, this, _1));
-}
-
-void
-Nfdc::ribUnregisterPrefix()
-{
-  m_name = m_commandLineArguments[0];
-  const std::string& faceName = m_commandLineArguments[1];
-
-  FaceIdFetcher::start(m_face, m_controller, faceName, false,
-                       [this] (const uint32_t faceId) {
-                         ControlParameters parameters;
-                         parameters
-                           .setName(m_name)
-                           .setFaceId(faceId)
-                           .setOrigin(m_origin);
-
-                         m_controller
-                           .start<RibUnregisterCommand>(parameters,
-                                                        bind(&Nfdc::onSuccess, this, _1,
-                                                             "Successful in unregistering name"),
-                                                        bind(&Nfdc::onError, this, _1, _2,
-                                                             "Failed in unregistering name"));
-                       },
-                       bind(&Nfdc::onObtainFaceIdFailure, this, _1));
-}
-
-void
-Nfdc::onCanonizeFailure(const std::string& reason)
-{
-  BOOST_THROW_EXCEPTION(Error(reason));
-}
-
-void
-Nfdc::onObtainFaceIdFailure(const std::string& message)
-{
-  BOOST_THROW_EXCEPTION(Error(message));
-}
-
-void
-Nfdc::faceCreate()
-{
-  boost::regex e("^[a-z0-9]+\\:.*");
-  if (!boost::regex_match(m_commandLineArguments[0], e))
-    BOOST_THROW_EXCEPTION(Error("invalid uri format"));
-
-  ndn::util::FaceUri faceUri;
-  faceUri.parse(m_commandLineArguments[0]);
-
-  faceUri.canonize(bind(&Nfdc::startFaceCreate, this, _1),
-                   bind(&Nfdc::onCanonizeFailure, this, _1),
-                   m_ioService, ndn::time::seconds(4));
-}
-
-void
-Nfdc::startFaceCreate(const ndn::util::FaceUri& canonicalUri)
-{
-  ControlParameters parameters;
-  parameters.setUri(canonicalUri.toString());
-  parameters.setFacePersistency(m_facePersistency);
-
-  m_controller.start<FaceCreateCommand>(parameters,
-                                        bind(&Nfdc::onSuccess, this, _1,
-                                             "Face creation succeeded"),
-                                        bind(&Nfdc::onError, this, _1, _2,
-                                             "Face creation failed"));
-}
-
-void
-Nfdc::faceDestroy()
-{
-  ControlParameters parameters;
-  const std::string& faceName = m_commandLineArguments[0];
-
-  FaceIdFetcher::start(m_face, m_controller, faceName, false,
-                       [this] (const uint32_t faceId) {
-                         ControlParameters faceParameters;
-                         faceParameters.setFaceId(faceId);
-
-                         m_controller.start<FaceDestroyCommand>(faceParameters,
-                                                                bind(&Nfdc::onSuccess, this, _1,
-                                                                     "Face destroy succeeded"),
-                                                                bind(&Nfdc::onError, this, _1, _2,
-                                                                     "Face destroy failed"));
-                       },
-                       bind(&Nfdc::onObtainFaceIdFailure, this, _1));
-}
-
-void
-Nfdc::strategyChoiceSet()
-{
-  const std::string& name = m_commandLineArguments[0];
-  const std::string& strategy = m_commandLineArguments[1];
-
-  ControlParameters parameters;
-  parameters
-    .setName(name)
-    .setStrategy(strategy);
-
-  m_controller.start<StrategyChoiceSetCommand>(parameters,
-                                               bind(&Nfdc::onSuccess, this, _1,
-                                                    "Successfully set strategy choice"),
-                                               bind(&Nfdc::onError, this, _1, _2,
-                                                    "Failed to set strategy choice"));
-}
-
-void
-Nfdc::strategyChoiceUnset()
-{
-  const std::string& name = m_commandLineArguments[0];
-
-  ControlParameters parameters;
-  parameters.setName(name);
-
-  m_controller.start<StrategyChoiceUnsetCommand>(parameters,
-                                                 bind(&Nfdc::onSuccess, this, _1,
-                                                      "Successfully unset strategy choice"),
-                                                 bind(&Nfdc::onError, this, _1, _2,
-                                                      "Failed to unset strategy choice"));
-}
-
-void
-Nfdc::onSuccess(const ControlParameters& commandSuccessResult, const std::string& message)
-{
-  std::cout << message << ": " << commandSuccessResult << std::endl;
-}
-
-void
-Nfdc::onError(uint32_t code, const std::string& error, const std::string& message)
-{
-  std::ostringstream os;
-  os << message << ": " << error << " (code: " << code << ")";
-  BOOST_THROW_EXCEPTION(Error(os.str()));
-}
-
-} // namespace nfdc
-
-int
-main(int argc, char** argv)
-{
-  ndn::Face face;
-  nfdc::Nfdc p(face);
-
-  p.m_programName = argv[0];
-
-  if (argc < 2) {
-    usage(p.m_programName);
-    return 0;
-  }
-
-  if (!strcmp(argv[1], "-h")) {
-    usage(p.m_programName);
-    return 0;
-  }
-
-  if (!strcmp(argv[1], "-V")) {
-    std::cout << NFD_VERSION_BUILD_STRING << std::endl;
-    return 0;
-  }
-
-  ::optind = 2; //start reading options from 2nd argument i.e. Command
-  int opt;
-  while ((opt = ::getopt(argc, argv, "ICc:e:o:P")) != -1) {
-    switch (opt) {
-      case 'I':
-        p.m_flags = p.m_flags & ~(nfdc::ROUTE_FLAG_CHILD_INHERIT);
-        break;
-
-      case 'C':
-        p.m_flags = p.m_flags | nfdc::ROUTE_FLAG_CAPTURE;
-        break;
-
-      case 'c':
-        try {
-          p.m_cost = boost::lexical_cast<uint64_t>(::optarg);
-        }
-        catch (boost::bad_lexical_cast&) {
-          std::cerr << "Error: cost must be in unsigned integer format" << std::endl;
-          return 1;
-        }
-        break;
-
-      case 'e':
-        uint64_t expires;
-        try {
-          expires = boost::lexical_cast<uint64_t>(::optarg);
-        }
-        catch (boost::bad_lexical_cast&) {
-          std::cerr << "Error: expiration time must be in unsigned integer format" << std::endl;
-          return 1;
-        }
-        p.m_expires = ndn::time::milliseconds(expires);
-        break;
-
-      case 'o':
-        try {
-          p.m_origin = boost::lexical_cast<uint64_t>(::optarg);
-        }
-        catch (boost::bad_lexical_cast&) {
-          std::cerr << "Error: origin must be in unsigned integer format" << std::endl;
-          return 1;
-        }
-        break;
-
-      case 'P':
-        p.m_facePersistency = ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERMANENT;
-        break;
-
-      default:
-        usage(p.m_programName);
-        return 1;
-    }
-  }
-
-  if (argc == ::optind) {
-    usage(p.m_programName);
-    return 1;
-  }
-
-  try {
-    p.m_commandLineArguments = argv + ::optind;
-    p.m_nOptions = argc - ::optind;
-
-    //argv[1] points to the command, so pass it to the dispatch
-    bool isOk = p.dispatch(argv[1]);
-    if (!isOk) {
-      usage(p.m_programName);
-      return 1;
-    }
-    face.processEvents();
-  }
-  catch (const std::exception& e) {
-    std::cerr << "ERROR: " << e.what() << std::endl;
-    return 2;
-  }
-  return 0;
-}
diff --git a/tools/nfdc.hpp b/tools/nfdc.hpp
deleted file mode 100644
index 3928ae5..0000000
--- a/tools/nfdc.hpp
+++ /dev/null
@@ -1,260 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014,  Regents of the University of California,
- *                      Arizona Board of Regents,
- *                      Colorado State University,
- *                      University Pierre & Marie Curie, Sorbonne University,
- *                      Washington University in St. Louis,
- *                      Beijing Institute of Technology,
- *                      The University of Memphis
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NFD_TOOLS_NFDC_HPP
-#define NFD_TOOLS_NFDC_HPP
-
-#include <ndn-cxx/face.hpp>
-#include <ndn-cxx/security/key-chain.hpp>
-#include <ndn-cxx/util/time.hpp>
-#include <ndn-cxx/management/nfd-controller.hpp>
-#include <ndn-cxx/util/face-uri.hpp>
-#include <ndn-cxx/security/validator-null.hpp>
-#include <memory>
-
-namespace nfdc {
-
-using namespace ndn::nfd;
-
-class Nfdc : boost::noncopyable
-{
-public:
-
-  static const ndn::time::milliseconds DEFAULT_EXPIRATION_PERIOD;
-  static const uint64_t DEFAULT_COST;
-
-  class Error : public std::runtime_error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : std::runtime_error(what)
-    {
-    }
-  };
-
-  class FaceIdFetcher
-  {
-  public:
-    typedef std::function<void(uint32_t)> SuccessCallback;
-    typedef std::function<void(const std::string&)> FailureCallback;
-
-    /** \brief obtain FaceId from input
-     *  \param face Reference to the Face that should be used to fetch data
-     *  \param controller Reference to the controller that should be used to sign the Interest
-     *  \param input User input, either FaceId or FaceUri
-     *  \param allowCreate Whether creating face is allowed
-     *  \param onSucceed Callback to be fired when faceId is obtained
-     *  \param onFail Callback to be fired when an error occurs
-     */
-    static void
-    start(ndn::Face& face,
-          Controller& controller,
-          const std::string& input,
-          bool allowCreate,
-          const SuccessCallback& onSucceed,
-          const FailureCallback& onFail);
-
-  private:
-    FaceIdFetcher(ndn::Face& face,
-                  Controller& controller,
-                  bool allowCreate,
-                  const SuccessCallback& onSucceed,
-                  const FailureCallback& onFail);
-
-    void
-    onQuerySuccess(const ndn::ConstBufferPtr& data,
-                   const ndn::util::FaceUri& canonicalUri);
-
-    void
-    onQueryFailure(uint32_t errorCode,
-                   const ndn::util::FaceUri& canonicalUri);
-
-    void
-    onCanonizeSuccess(const ndn::util::FaceUri& canonicalUri);
-
-    void
-    onCanonizeFailure(const std::string& reason);
-
-    void
-    startGetFaceId(const ndn::util::FaceUri& faceUri);
-
-    void
-    startFaceCreate(const ndn::util::FaceUri& canonicalUri);
-
-    void
-    onFaceCreateError(uint32_t code,
-                      const std::string& error,
-                      const std::string& message);
-
-    void
-    succeed(uint32_t faceId);
-
-    void
-    fail(const std::string& reason);
-
-  private:
-    ndn::Face& m_face;
-    Controller& m_controller;
-    bool m_allowCreate;
-    SuccessCallback m_onSucceed;
-    FailureCallback m_onFail;
-    ndn::ValidatorNull m_validator;
-  };
-
-  explicit
-  Nfdc(ndn::Face& face);
-
-  ~Nfdc();
-
-  bool
-  dispatch(const std::string& cmd);
-
-  /**
-   * \brief Adds a nexthop to a FIB entry
-   *
-   * If the FIB entry does not exist, it is inserted automatically
-   *
-   * cmd format:
-   *  [-c cost]  name faceId|faceUri
-   *
-   */
-  void
-  fibAddNextHop();
-
-  /**
-   * \brief Removes a nexthop from an existing FIB entry
-   *
-   * If the last nexthop record in a FIB entry is removed, the FIB entry is also deleted
-   *
-   * cmd format:
-   *  name faceId
-   *
-   */
-  void
-  fibRemoveNextHop();
-
-  /**
-   * \brief Registers name to the given faceId or faceUri
-   *
-   * cmd format:
-   *  [-I] [-C] [-c cost] name faceId|faceUri
-   */
-  void
-  ribRegisterPrefix();
-
-  /**
-   * \brief Unregisters name from the given faceId/faceUri
-   *
-   * cmd format:
-   *  name faceId/faceUri
-   */
-  void
-  ribUnregisterPrefix();
-
-  /**
-   * \brief Creates new face
-   *
-   * This command allows creation of UDP unicast and TCP faces only
-   *
-   * cmd format:
-   *  uri
-   *
-   */
-  void
-  faceCreate();
-
-  /**
-   * \brief Destroys face
-   *
-   * cmd format:
-   *  faceId|faceUri
-   *
-   */
-  void
-  faceDestroy();
-
-  /**
-   * \brief Sets the strategy for a namespace
-   *
-   * cmd format:
-   *  name strategy
-   *
-   */
-  void
-  strategyChoiceSet();
-
-  /**
-   * \brief Unset the strategy for a namespace
-   *
-   * cmd format:
-   *  name strategy
-   *
-   */
-  void
-  strategyChoiceUnset();
-
-private:
-
-  void
-  onSuccess(const ControlParameters& commandSuccessResult,
-            const std::string& message);
-
-  void
-  onError(uint32_t code, const std::string& error, const std::string& message);
-
-  void
-  onCanonizeFailure(const std::string& reason);
-
-  void
-  startFaceCreate(const ndn::util::FaceUri& canonicalUri);
-
-  void
-  onObtainFaceIdFailure(const std::string& message);
-
-public:
-  const char* m_programName;
-
-  // command parameters without leading 'cmd' component
-  const char* const* m_commandLineArguments;
-  int m_nOptions;
-  uint64_t m_flags;
-  uint64_t m_cost;
-  uint64_t m_faceId;
-  uint64_t m_origin;
-  ndn::time::milliseconds m_expires;
-  std::string m_name;
-  FacePersistency m_facePersistency;
-
-private:
-  ndn::KeyChain m_keyChain;
-  ndn::Face& m_face;
-  Controller m_controller;
-  boost::asio::io_service& m_ioService;
-};
-
-} // namespace nfdc
-
-#endif // NFD_TOOLS_NFDC_HPP
diff --git a/tools/nfdc/face-id-fetcher.cpp b/tools/nfdc/face-id-fetcher.cpp
new file mode 100644
index 0000000..da09c11
--- /dev/null
+++ b/tools/nfdc/face-id-fetcher.cpp
@@ -0,0 +1,203 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "face-id-fetcher.hpp"
+
+#include <boost/lexical_cast.hpp>
+#include <boost/regex.hpp>
+
+#include <ndn-cxx/management/nfd-face-query-filter.hpp>
+#include <ndn-cxx/management/nfd-face-status.hpp>
+#include <ndn-cxx/util/segment-fetcher.hpp>
+
+namespace nfd {
+namespace tools {
+namespace nfdc {
+
+FaceIdFetcher::FaceIdFetcher(ndn::Face& face,
+                             ndn::nfd::Controller& controller,
+                             bool allowCreate,
+                             const SuccessCallback& onSucceed,
+                             const FailureCallback& onFail)
+  : m_face(face)
+  , m_controller(controller)
+  , m_allowCreate(allowCreate)
+  , m_onSucceed(onSucceed)
+  , m_onFail(onFail)
+{
+}
+
+void
+FaceIdFetcher::start(ndn::Face& face,
+                     ndn::nfd::Controller& controller,
+                     const std::string& input,
+                     bool allowCreate,
+                     const SuccessCallback& onSucceed,
+                     const FailureCallback& onFail)
+{
+  // 1. Try parse input as FaceId, if input is FaceId, succeed with parsed FaceId
+  // 2. Try parse input as FaceUri, if input is not FaceUri, fail
+  // 3. Canonize faceUri
+  // 4. If canonization fails, fail
+  // 5. Query for face
+  // 6. If query succeeds and finds a face, succeed with found FaceId
+  // 7. Create face
+  // 8. If face creation succeeds, succeed with created FaceId
+  // 9. Fail
+
+  boost::regex e("^[a-z0-9]+\\:.*");
+  if (!boost::regex_match(input, e)) {
+    try {
+      uint32_t faceId = boost::lexical_cast<uint32_t>(input);
+      onSucceed(faceId);
+      return;
+    }
+    catch (const boost::bad_lexical_cast&) {
+      onFail("No valid faceId or faceUri is provided");
+      return;
+    }
+  }
+  else {
+    FaceUri faceUri;
+    if (!faceUri.parse(input)) {
+      onFail("FaceUri parse failed");
+      return;
+    }
+
+    auto fetcher = new FaceIdFetcher(std::ref(face), std::ref(controller),
+                                     allowCreate, onSucceed, onFail);
+    fetcher->startGetFaceId(faceUri);
+  }
+}
+
+void
+FaceIdFetcher::startGetFaceId(const FaceUri& faceUri)
+{
+  faceUri.canonize(bind(&FaceIdFetcher::onCanonizeSuccess, this, _1),
+                   bind(&FaceIdFetcher::onCanonizeFailure, this, _1),
+                   m_face.getIoService(), time::seconds(4));
+}
+
+void
+FaceIdFetcher::onCanonizeSuccess(const FaceUri& canonicalUri)
+{
+  ndn::Name queryName("/localhost/nfd/faces/query");
+  ndn::nfd::FaceQueryFilter queryFilter;
+  queryFilter.setRemoteUri(canonicalUri.toString());
+  queryName.append(queryFilter.wireEncode());
+
+  ndn::Interest interestPacket(queryName);
+  interestPacket.setMustBeFresh(true);
+  interestPacket.setInterestLifetime(time::milliseconds(4000));
+  auto interest = std::make_shared<ndn::Interest>(interestPacket);
+
+  ndn::util::SegmentFetcher::fetch(
+    m_face, *interest, m_validator,
+    bind(&FaceIdFetcher::onQuerySuccess, this, _1, canonicalUri),
+    bind(&FaceIdFetcher::onQueryFailure, this, _1, canonicalUri));
+}
+
+void
+FaceIdFetcher::onCanonizeFailure(const std::string& reason)
+{
+  fail("Canonize faceUri failed : " + reason);
+}
+
+void
+FaceIdFetcher::onQuerySuccess(const ndn::ConstBufferPtr& data,
+                              const FaceUri& canonicalUri)
+{
+  size_t offset = 0;
+  bool isOk = false;
+  ndn::Block block;
+  std::tie(isOk, block) = ndn::Block::fromBuffer(data, offset);
+
+  if (!isOk) {
+    if (m_allowCreate) {
+      startFaceCreate(canonicalUri);
+    }
+    else {
+      fail("Fail to find faceId");
+    }
+  }
+  else {
+    try {
+      ndn::nfd::FaceStatus status(block);
+      succeed(status.getFaceId());
+    }
+    catch (const ndn::tlv::Error& e) {
+      std::string errorMessage(e.what());
+      fail("ERROR: " + errorMessage);
+    }
+  }
+}
+
+void
+FaceIdFetcher::onQueryFailure(uint32_t errorCode,
+                              const FaceUri& canonicalUri)
+{
+  std::stringstream ss;
+  ss << "Cannot fetch data (code " << errorCode << ")";
+  fail(ss.str());
+}
+
+void
+FaceIdFetcher::onFaceCreateError(uint32_t code,
+                                 const std::string& error,
+                                 const std::string& message)
+{
+  std::stringstream ss;
+  ss << message << " : " << error << " (code " << code << ")";
+  fail(ss.str());
+}
+
+void
+FaceIdFetcher::startFaceCreate(const FaceUri& canonicalUri)
+{
+  ndn::nfd::ControlParameters parameters;
+  parameters.setUri(canonicalUri.toString());
+
+  m_controller.start<ndn::nfd::FaceCreateCommand>(parameters,
+    [this] (const ndn::nfd::ControlParameters& result) { succeed(result.getFaceId()); },
+    bind(&FaceIdFetcher::onFaceCreateError, this, _1, _2, "Face creation failed"));
+}
+
+void
+FaceIdFetcher::succeed(uint32_t faceId)
+{
+  m_onSucceed(faceId);
+  delete this;
+}
+
+void
+FaceIdFetcher::fail(const std::string& reason)
+{
+  m_onFail(reason);
+  delete this;
+}
+
+} // namespace nfdc
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfdc/face-id-fetcher.hpp b/tools/nfdc/face-id-fetcher.hpp
new file mode 100644
index 0000000..50e0083
--- /dev/null
+++ b/tools/nfdc/face-id-fetcher.hpp
@@ -0,0 +1,114 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_TOOLS_NFDC_FACE_ID_FETCHER_HPP
+#define NFD_TOOLS_NFDC_FACE_ID_FETCHER_HPP
+
+#include "core/common.hpp"
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/management/nfd-controller.hpp>
+#include <ndn-cxx/util/face-uri.hpp>
+#include <ndn-cxx/security/validator-null.hpp>
+
+namespace nfd {
+namespace tools {
+namespace nfdc {
+
+using ndn::util::FaceUri;
+
+class FaceIdFetcher
+{
+public:
+  typedef std::function<void(uint32_t)> SuccessCallback;
+  typedef std::function<void(const std::string&)> FailureCallback;
+
+  /** \brief obtain FaceId from input
+   *  \param face Reference to the Face that should be used to fetch data
+   *  \param controller Reference to the controller that should be used to sign the Interest
+   *  \param input User input, either FaceId or FaceUri
+   *  \param allowCreate Whether creating face is allowed
+   *  \param onSucceed Callback to be fired when faceId is obtained
+   *  \param onFail Callback to be fired when an error occurs
+   */
+  static void
+  start(ndn::Face& face,
+        ndn::nfd::Controller& controller,
+        const std::string& input,
+        bool allowCreate,
+        const SuccessCallback& onSucceed,
+        const FailureCallback& onFail);
+
+private:
+  FaceIdFetcher(ndn::Face& face,
+                ndn::nfd::Controller& controller,
+                bool allowCreate,
+                const SuccessCallback& onSucceed,
+                const FailureCallback& onFail);
+
+  void
+  onQuerySuccess(const ndn::ConstBufferPtr& data,
+                 const FaceUri& canonicalUri);
+
+  void
+  onQueryFailure(uint32_t errorCode,
+                 const FaceUri& canonicalUri);
+
+  void
+  onCanonizeSuccess(const FaceUri& canonicalUri);
+
+  void
+  onCanonizeFailure(const std::string& reason);
+
+  void
+  startGetFaceId(const FaceUri& faceUri);
+
+  void
+  startFaceCreate(const FaceUri& canonicalUri);
+
+  void
+  onFaceCreateError(uint32_t code,
+                    const std::string& error,
+                    const std::string& message);
+
+  void
+  succeed(uint32_t faceId);
+
+  void
+  fail(const std::string& reason);
+
+private:
+  ndn::Face& m_face;
+  ndn::nfd::Controller& m_controller;
+  bool m_allowCreate;
+  SuccessCallback m_onSucceed;
+  FailureCallback m_onFail;
+  ndn::ValidatorNull m_validator;
+};
+
+} // namespace nfdc
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFDC_FACE_ID_FETCHER_HPP
diff --git a/tools/nfdc/legacy-nfdc.cpp b/tools/nfdc/legacy-nfdc.cpp
new file mode 100644
index 0000000..83a3db8
--- /dev/null
+++ b/tools/nfdc/legacy-nfdc.cpp
@@ -0,0 +1,290 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "legacy-nfdc.hpp"
+#include "face-id-fetcher.hpp"
+
+#include <boost/regex.hpp>
+
+namespace nfd {
+namespace tools {
+namespace nfdc {
+
+using ndn::nfd::ControlParameters;
+
+const time::milliseconds LegacyNfdc::DEFAULT_EXPIRATION_PERIOD = time::milliseconds::max();
+const uint64_t LegacyNfdc::DEFAULT_COST = 0;
+
+LegacyNfdc::LegacyNfdc(ndn::Face& face)
+  : m_flags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT)
+  , m_cost(DEFAULT_COST)
+  , m_origin(ndn::nfd::ROUTE_ORIGIN_STATIC)
+  , m_expires(DEFAULT_EXPIRATION_PERIOD)
+  , m_facePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
+  , m_face(face)
+  , m_controller(face, m_keyChain)
+{
+}
+
+bool
+LegacyNfdc::dispatch(const std::string& command)
+{
+  if (command == "add-nexthop") {
+    if (m_nOptions != 2)
+      return false;
+    fibAddNextHop();
+  }
+  else if (command == "remove-nexthop") {
+    if (m_nOptions != 2)
+      return false;
+    fibRemoveNextHop();
+  }
+  else if (command == "register") {
+    if (m_nOptions != 2)
+      return false;
+    ribRegisterPrefix();
+  }
+  else if (command == "unregister") {
+    if (m_nOptions != 2)
+      return false;
+    ribUnregisterPrefix();
+  }
+  else if (command == "create") {
+    if (m_nOptions != 1)
+      return false;
+    faceCreate();
+  }
+  else if (command == "destroy") {
+    if (m_nOptions != 1)
+      return false;
+    faceDestroy();
+  }
+  else if (command == "set-strategy") {
+    if (m_nOptions != 2)
+      return false;
+    strategyChoiceSet();
+  }
+  else if (command == "unset-strategy") {
+    if (m_nOptions != 1)
+      return false;
+    strategyChoiceUnset();
+  }
+  else
+    return false;
+
+  return true;
+}
+
+void
+LegacyNfdc::fibAddNextHop()
+{
+  m_name = m_commandLineArguments[0];
+  const std::string& faceName = m_commandLineArguments[1];
+
+  FaceIdFetcher::start(m_face, m_controller, faceName, true,
+    [this] (const uint32_t faceId) {
+      ControlParameters parameters;
+      parameters
+        .setName(m_name)
+        .setCost(m_cost)
+        .setFaceId(faceId);
+
+      m_controller.start<ndn::nfd::FibAddNextHopCommand>(parameters,
+        bind(&LegacyNfdc::onSuccess, this, _1, "Nexthop insertion succeeded"),
+        bind(&LegacyNfdc::onError, this, _1, _2, "Nexthop insertion failed"));
+    },
+    bind(&LegacyNfdc::onObtainFaceIdFailure, this, _1));
+}
+
+void
+LegacyNfdc::fibRemoveNextHop()
+{
+  m_name = m_commandLineArguments[0];
+  const std::string& faceName = m_commandLineArguments[1];
+
+  FaceIdFetcher::start(m_face, m_controller, faceName, false,
+    [this] (const uint32_t faceId) {
+      ControlParameters parameters;
+      parameters
+        .setName(m_name)
+        .setFaceId(faceId);
+
+      m_controller.start<ndn::nfd::FibRemoveNextHopCommand>(parameters,
+        bind(&LegacyNfdc::onSuccess, this, _1, "Nexthop removal succeeded"),
+        bind(&LegacyNfdc::onError, this, _1, _2, "Nexthop removal failed"));
+    },
+    bind(&LegacyNfdc::onObtainFaceIdFailure, this, _1));
+}
+
+void
+LegacyNfdc::ribRegisterPrefix()
+{
+  m_name = m_commandLineArguments[0];
+  const std::string& faceName = m_commandLineArguments[1];
+
+  FaceIdFetcher::start(m_face, m_controller, faceName, true,
+    [this] (const uint32_t faceId) {
+      ControlParameters parameters;
+      parameters
+        .setName(m_name)
+        .setCost(m_cost)
+        .setFlags(m_flags)
+        .setOrigin(m_origin)
+        .setFaceId(faceId);
+
+      if (m_expires != DEFAULT_EXPIRATION_PERIOD)
+        parameters.setExpirationPeriod(m_expires);
+
+      m_controller.start<ndn::nfd::RibRegisterCommand>(parameters,
+        bind(&LegacyNfdc::onSuccess, this, _1, "Successful in name registration"),
+        bind(&LegacyNfdc::onError, this, _1, _2, "Failed in name registration"));
+    },
+    bind(&LegacyNfdc::onObtainFaceIdFailure, this, _1));
+}
+
+void
+LegacyNfdc::ribUnregisterPrefix()
+{
+  m_name = m_commandLineArguments[0];
+  const std::string& faceName = m_commandLineArguments[1];
+
+  FaceIdFetcher::start(m_face, m_controller, faceName, false,
+    [this] (const uint32_t faceId) {
+      ControlParameters parameters;
+      parameters
+        .setName(m_name)
+        .setFaceId(faceId)
+        .setOrigin(m_origin);
+
+      m_controller.start<ndn::nfd::RibUnregisterCommand>(parameters,
+        bind(&LegacyNfdc::onSuccess, this, _1, "Successful in unregistering name"),
+        bind(&LegacyNfdc::onError, this, _1, _2, "Failed in unregistering name"));
+    },
+    bind(&LegacyNfdc::onObtainFaceIdFailure, this, _1));
+}
+
+void
+LegacyNfdc::onCanonizeFailure(const std::string& reason)
+{
+  BOOST_THROW_EXCEPTION(Error(reason));
+}
+
+void
+LegacyNfdc::onObtainFaceIdFailure(const std::string& message)
+{
+  BOOST_THROW_EXCEPTION(Error(message));
+}
+
+void
+LegacyNfdc::faceCreate()
+{
+  boost::regex e("^[a-z0-9]+\\:.*");
+  if (!boost::regex_match(m_commandLineArguments[0], e))
+    BOOST_THROW_EXCEPTION(Error("invalid uri format"));
+
+  FaceUri faceUri;
+  faceUri.parse(m_commandLineArguments[0]);
+
+  faceUri.canonize(bind(&LegacyNfdc::startFaceCreate, this, _1),
+                   bind(&LegacyNfdc::onCanonizeFailure, this, _1),
+                   m_face.getIoService(), time::seconds(4));
+}
+
+void
+LegacyNfdc::startFaceCreate(const FaceUri& canonicalUri)
+{
+  ControlParameters parameters;
+  parameters.setUri(canonicalUri.toString());
+  parameters.setFacePersistency(m_facePersistency);
+
+  m_controller.start<ndn::nfd::FaceCreateCommand>(parameters,
+    bind(&LegacyNfdc::onSuccess, this, _1, "Face creation succeeded"),
+    bind(&LegacyNfdc::onError, this, _1, _2, "Face creation failed"));
+}
+
+void
+LegacyNfdc::faceDestroy()
+{
+  ControlParameters parameters;
+  const std::string& faceName = m_commandLineArguments[0];
+
+  FaceIdFetcher::start(m_face, m_controller, faceName, false,
+    [this] (const uint32_t faceId) {
+      ControlParameters faceParameters;
+      faceParameters.setFaceId(faceId);
+
+      m_controller.start<ndn::nfd::FaceDestroyCommand>(faceParameters,
+        bind(&LegacyNfdc::onSuccess, this, _1, "Face destroy succeeded"),
+        bind(&LegacyNfdc::onError, this, _1, _2, "Face destroy failed"));
+    },
+    bind(&LegacyNfdc::onObtainFaceIdFailure, this, _1));
+}
+
+void
+LegacyNfdc::strategyChoiceSet()
+{
+  const std::string& name = m_commandLineArguments[0];
+  const std::string& strategy = m_commandLineArguments[1];
+
+  ControlParameters parameters;
+  parameters
+    .setName(name)
+    .setStrategy(strategy);
+
+  m_controller.start<ndn::nfd::StrategyChoiceSetCommand>(parameters,
+    bind(&LegacyNfdc::onSuccess, this, _1, "Successfully set strategy choice"),
+    bind(&LegacyNfdc::onError, this, _1, _2, "Failed to set strategy choice"));
+}
+
+void
+LegacyNfdc::strategyChoiceUnset()
+{
+  const std::string& name = m_commandLineArguments[0];
+
+  ControlParameters parameters;
+  parameters.setName(name);
+
+  m_controller.start<ndn::nfd::StrategyChoiceUnsetCommand>(parameters,
+    bind(&LegacyNfdc::onSuccess, this, _1, "Successfully unset strategy choice"),
+    bind(&LegacyNfdc::onError, this, _1, _2, "Failed to unset strategy choice"));
+}
+
+void
+LegacyNfdc::onSuccess(const ControlParameters& commandSuccessResult, const std::string& message)
+{
+  std::cout << message << ": " << commandSuccessResult << std::endl;
+}
+
+void
+LegacyNfdc::onError(uint32_t code, const std::string& error, const std::string& message)
+{
+  std::ostringstream os;
+  os << message << ": " << error << " (code: " << code << ")";
+  BOOST_THROW_EXCEPTION(Error(os.str()));
+}
+
+} // namespace nfdc
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfdc/legacy-nfdc.hpp b/tools/nfdc/legacy-nfdc.hpp
new file mode 100644
index 0000000..01ed7b9
--- /dev/null
+++ b/tools/nfdc/legacy-nfdc.hpp
@@ -0,0 +1,186 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_TOOLS_NFDC_LEGACY_NFDC_HPP
+#define NFD_TOOLS_NFDC_LEGACY_NFDC_HPP
+
+#include "core/common.hpp"
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/management/nfd-controller.hpp>
+
+namespace nfd {
+namespace tools {
+namespace nfdc {
+
+class LegacyNfdc : noncopyable
+{
+public:
+  static const time::milliseconds DEFAULT_EXPIRATION_PERIOD;
+  static const uint64_t DEFAULT_COST;
+
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+  explicit
+  LegacyNfdc(ndn::Face& face);
+
+  bool
+  dispatch(const std::string& cmd);
+
+  /**
+   * \brief Adds a nexthop to a FIB entry
+   *
+   * If the FIB entry does not exist, it is inserted automatically
+   *
+   * cmd format:
+   *  [-c cost]  name faceId|faceUri
+   *
+   */
+  void
+  fibAddNextHop();
+
+  /**
+   * \brief Removes a nexthop from an existing FIB entry
+   *
+   * If the last nexthop record in a FIB entry is removed, the FIB entry is also deleted
+   *
+   * cmd format:
+   *  name faceId
+   *
+   */
+  void
+  fibRemoveNextHop();
+
+  /**
+   * \brief Registers name to the given faceId or faceUri
+   *
+   * cmd format:
+   *  [-I] [-C] [-c cost] name faceId|faceUri
+   */
+  void
+  ribRegisterPrefix();
+
+  /**
+   * \brief Unregisters name from the given faceId/faceUri
+   *
+   * cmd format:
+   *  name faceId/faceUri
+   */
+  void
+  ribUnregisterPrefix();
+
+  /**
+   * \brief Creates new face
+   *
+   * This command allows creation of UDP unicast and TCP faces only
+   *
+   * cmd format:
+   *  uri
+   *
+   */
+  void
+  faceCreate();
+
+  /**
+   * \brief Destroys face
+   *
+   * cmd format:
+   *  faceId|faceUri
+   *
+   */
+  void
+  faceDestroy();
+
+  /**
+   * \brief Sets the strategy for a namespace
+   *
+   * cmd format:
+   *  name strategy
+   *
+   */
+  void
+  strategyChoiceSet();
+
+  /**
+   * \brief Unset the strategy for a namespace
+   *
+   * cmd format:
+   *  name strategy
+   *
+   */
+  void
+  strategyChoiceUnset();
+
+private:
+
+  void
+  onSuccess(const ndn::nfd::ControlParameters& commandSuccessResult,
+            const std::string& message);
+
+  void
+  onError(uint32_t code, const std::string& error, const std::string& message);
+
+  void
+  onCanonizeFailure(const std::string& reason);
+
+  void
+  startFaceCreate(const ndn::util::FaceUri& canonicalUri);
+
+  void
+  onObtainFaceIdFailure(const std::string& message);
+
+public:
+  const char* m_programName;
+
+  // command parameters without leading 'cmd' component
+  const char* const* m_commandLineArguments;
+  int m_nOptions;
+  uint64_t m_flags;
+  uint64_t m_cost;
+  uint64_t m_faceId;
+  uint64_t m_origin;
+  time::milliseconds m_expires;
+  std::string m_name;
+  ndn::nfd::FacePersistency m_facePersistency;
+
+private:
+  ndn::KeyChain m_keyChain;
+  ndn::Face& m_face;
+  ndn::nfd::Controller m_controller;
+};
+
+} // namespace nfdc
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFDC_LEGACY_NFDC_HPP
diff --git a/tools/nfdc/main.cpp b/tools/nfdc/main.cpp
new file mode 100644
index 0000000..7d9f763
--- /dev/null
+++ b/tools/nfdc/main.cpp
@@ -0,0 +1,182 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "legacy-nfdc.hpp"
+#include "core/version.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+namespace nfd {
+namespace tools {
+namespace nfdc {
+
+static void
+usage(const char* programName)
+{
+  std::cout << "Usage:\n" << programName  << " [-h] [-V] COMMAND [<Command Options>]\n"
+    "       -h print usage and exit\n"
+    "       -V print version and exit\n"
+    "\n"
+    "   COMMAND can be one of the following:\n"
+    "       register [-I] [-C] [-c cost] [-e expiration time] [-o origin] name <faceId | faceUri>\n"
+    "           register name to the given faceId or faceUri\n"
+    "           -I: unset CHILD_INHERIT flag\n"
+    "           -C: set CAPTURE flag\n"
+    "           -c: specify cost (default 0)\n"
+    "           -e: specify expiration time in ms\n"
+    "               (by default the entry remains in FIB for the lifetime of the associated face)\n"
+    "           -o: specify origin\n"
+    "               0 for Local producer applications, 128 for NLSR, 255(default) for static routes\n"
+    "       unregister [-o origin] name <faceId | faceUri>\n"
+    "           unregister name from the given faceId\n"
+    "       create [-P] <faceUri> \n"
+    "           Create a face in one of the following formats:\n"
+    "           UDP unicast:    udp[4|6]://<remote-IP-or-host>[:<remote-port>]\n"
+    "           TCP:            tcp[4|6]://<remote-IP-or-host>[:<remote-port>] \n"
+    "           -P: create permanent (instead of persistent) face\n"
+    "       destroy <faceId | faceUri> \n"
+    "           Destroy a face\n"
+    "       set-strategy <name> <strategy> \n"
+    "           Set the strategy for a namespace \n"
+    "       unset-strategy <name> \n"
+    "           Unset the strategy for a namespace \n"
+    "       add-nexthop [-c <cost>] <name> <faceId | faceUri>\n"
+    "           Add a nexthop to a FIB entry\n"
+    "           -c: specify cost (default 0)\n"
+    "       remove-nexthop <name> <faceId | faceUri> \n"
+    "           Remove a nexthop from a FIB entry\n"
+    << std::endl;
+}
+
+static int
+main(int argc, char** argv)
+{
+  ndn::Face face;
+  LegacyNfdc p(face);
+
+  p.m_programName = argv[0];
+
+  if (argc < 2) {
+    usage(p.m_programName);
+    return 0;
+  }
+
+  if (!strcmp(argv[1], "-h")) {
+    usage(p.m_programName);
+    return 0;
+  }
+
+  if (!strcmp(argv[1], "-V")) {
+    std::cout << NFD_VERSION_BUILD_STRING << std::endl;
+    return 0;
+  }
+
+  ::optind = 2; //start reading options from 2nd argument i.e. Command
+  int opt;
+  while ((opt = ::getopt(argc, argv, "ICc:e:o:P")) != -1) {
+    switch (opt) {
+      case 'I':
+        p.m_flags = p.m_flags & ~(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
+        break;
+
+      case 'C':
+        p.m_flags = p.m_flags | ndn::nfd::ROUTE_FLAG_CAPTURE;
+        break;
+
+      case 'c':
+        try {
+          p.m_cost = boost::lexical_cast<uint64_t>(::optarg);
+        }
+        catch (const boost::bad_lexical_cast&) {
+          std::cerr << "Error: cost must be in unsigned integer format" << std::endl;
+          return 1;
+        }
+        break;
+
+      case 'e':
+        uint64_t expires;
+        try {
+          expires = boost::lexical_cast<uint64_t>(::optarg);
+        }
+        catch (const boost::bad_lexical_cast&) {
+          std::cerr << "Error: expiration time must be in unsigned integer format" << std::endl;
+          return 1;
+        }
+        p.m_expires = ndn::time::milliseconds(expires);
+        break;
+
+      case 'o':
+        try {
+          p.m_origin = boost::lexical_cast<uint64_t>(::optarg);
+        }
+        catch (const boost::bad_lexical_cast&) {
+          std::cerr << "Error: origin must be in unsigned integer format" << std::endl;
+          return 1;
+        }
+        break;
+
+      case 'P':
+        p.m_facePersistency = ndn::nfd::FACE_PERSISTENCY_PERMANENT;
+        break;
+
+      default:
+        usage(p.m_programName);
+        return 1;
+    }
+  }
+
+  if (argc == ::optind) {
+    usage(p.m_programName);
+    return 1;
+  }
+
+  try {
+    p.m_commandLineArguments = argv + ::optind;
+    p.m_nOptions = argc - ::optind;
+
+    //argv[1] points to the command, so pass it to the dispatch
+    bool isOk = p.dispatch(argv[1]);
+    if (!isOk) {
+      usage(p.m_programName);
+      return 1;
+    }
+    face.processEvents();
+  }
+  catch (const std::exception& e) {
+    std::cerr << "ERROR: " << e.what() << std::endl;
+    return 2;
+  }
+  return 0;
+}
+
+} // namespace nfdc
+} // namespace tools
+} // namespace nfd
+
+int
+main(int argc, char** argv)
+{
+  return nfd::tools::nfdc::main(argc, argv);
+}