tools: nfdc

Change-Id: Ida7d3b4264fd3452acf69b443150e3ad639e3da9
diff --git a/tools/nfdc.cpp b/tools/nfdc.cpp
new file mode 100644
index 0000000..1ad54af
--- /dev/null
+++ b/tools/nfdc.cpp
@@ -0,0 +1,269 @@
+/* -*- 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 "nfdc.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/regex_find_format.hpp>
+#include <boost/regex.hpp>
+
+void
+usage(const char* programName)
+{
+  std::cout << "Usage:\n" << programName  << " [-h] COMMAND\n"
+  "       -h print usage and exit\n"
+  "\n"
+  "   COMMAND can be one of following:\n"
+  "       insert <name> \n"
+  "           Insert a FIB entry \n"
+  "       delete <name> \n"
+  "           Delete a FIB entry\n"
+  "       add-nexthop <name> <faceId> [<cost>]\n"
+  "           Add a nexthop to an existing FIB entry\n"
+  "       remove-nexthop <name> <faceId> \n"
+  "           Remove a nexthop from a FIB entry\n"
+  "       set-strategy <name> <stratgy>\n"
+  "           Set a forwarding strategy for a namespace\n"
+  "       create <uri> \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"
+  "       destroy <faceId> \n"
+  "           Destroy a face\n"
+  << std::endl;
+}
+
+namespace nfdc {
+  
+Controller::Controller(ndn::Face& face)
+  : ndn::nfd::Controller(face)
+{
+}
+  
+Controller::~Controller()
+{
+}
+bool
+Controller::dispatch(const std::string& command, const char* commandOptions[], int nOptions)
+{
+  if (command == "insert") {
+    if (nOptions != 1)
+      return false;
+    fibInsert(commandOptions);
+  }
+  else if (command == "delete") {
+    if (nOptions != 1)
+      return false;
+    fibDelete(commandOptions);
+  }
+  else if (command == "add-nexthop") {
+    if (nOptions == 2)
+      fibAddNextHop(commandOptions, false);
+    else if (nOptions == 3)
+      fibAddNextHop(commandOptions, true);
+    else
+      return false;
+  }
+  else if (command == "remove-nexthop") {
+    if (nOptions != 2)
+      return false;
+    fibRemoveNextHop(commandOptions);
+  }
+  else if (command == "set-strategy") {
+    if (nOptions != 2)
+      return false;
+    fibSetStrategy(commandOptions);
+  }
+  else if (command == "create") {
+    if (nOptions != 1)
+      return false;
+    faceCreate(commandOptions);
+  }
+  else if (command == "destroy") {
+    if (nOptions != 1)
+      return false;
+    faceDestroy(commandOptions);
+  }
+  else
+    usage(m_programName);
+
+  return true;
+}
+  
+void
+Controller::fibInsert(const char* commandOptions[])
+{
+  const std::string& name = commandOptions[0];
+
+  ndn::nfd::FibManagementOptions fibOptions;
+  fibOptions.setName(name);
+  startFibCommand("insert",
+                  fibOptions,
+                  bind(&Controller::onFibSuccess, this, _1, "Fib insertion succeeded"),
+                  bind(&Controller::onError, this, _1, "Fib insertion failed"));
+}
+    
+void
+Controller::fibDelete(const char* commandOptions[])
+{
+  const std::string& name = commandOptions[0];
+  ndn::nfd::FibManagementOptions fibOptions;
+  fibOptions.setName(name);
+  startFibCommand("delete",
+                  fibOptions,
+                  bind(&Controller::onFibSuccess, this, _1, "Fib deletion succeeded"),
+                  bind(&Controller::onError, this, _1, "Fib deletion failed" ));
+}
+
+
+void
+Controller::fibAddNextHop(const char* commandOptions[], bool hasCost)
+{
+  ndn::nfd::FibManagementOptions fibOptions;
+  
+  const std::string& name = commandOptions[0];
+  const int faceId = boost::lexical_cast<int>(commandOptions[1]);
+
+  fibOptions.setName(name);
+  fibOptions.setFaceId(faceId);
+
+  if (hasCost)
+  {
+    const int cost = boost::lexical_cast<int>(commandOptions[2]);
+    fibOptions.setCost(cost);
+  }
+  startFibCommand("add-nexthop",
+                  fibOptions,
+                  bind(&Controller::onFibSuccess, this, _1, "Nexthop insertion succeeded"),
+                  bind(&Controller::onError, this, _1, "Nexthop insertion failed"));
+}
+
+void
+Controller::fibRemoveNextHop(const char* commandOptions[])
+{
+  const std::string& name = commandOptions[0];
+  const int faceId = boost::lexical_cast<int>(commandOptions[1]);
+  ndn::nfd::FibManagementOptions fibOptions;
+
+  fibOptions.setName(name);
+  fibOptions.setFaceId(faceId);
+  startFibCommand("remove-nexthop",
+                  fibOptions,
+                  bind(&Controller::onFibSuccess, this, _1, "Nexthop Removal succeeded"),
+                  bind(&Controller::onError, this, _1, "Nexthop Removal failed"));
+}
+
+void
+Controller::fibSetStrategy(const char* commandOptions[])
+{
+    
+  // std::string name      = commandOptions[0];
+  // std::string strategy  = commandOptions[1];
+  // startFibCommand("set-strategy",
+  //                  ndn::nfd::FibManagementOptions()
+  //                  .setName(name)
+  //                  .setStrategy(strategy),
+  //                  bind(&Controller::onFibSuccess,this, _1),
+  //                  bind(&Controller::onError,this, _1));
+}
+ 
+namespace {
+bool
+isValidUri(const std::string& input)
+{
+  // an extended regex to support the validation of uri structure
+  // boost::regex e("^[a-z0-9]+-?+[a-z0-9]+\\:\\/\\/.*");
+  boost::regex e("^[a-z0-9]+\\:.*");
+  return boost::regex_match(input, e);
+}
+} // anonymous namespace
+
+void
+Controller::faceCreate(const char* commandOptions[])
+{
+  ndn::nfd::FaceManagementOptions faceOptions;
+  const std::string& uri = commandOptions[0];
+  faceOptions.setUri(uri);
+  
+  if (isValidUri(uri))
+  {
+    startFaceCommand("create",
+                     faceOptions,
+                     bind(&Controller::onFaceSuccess, this, _1, "Face creation succeeded"),
+                     bind(&Controller::onError, this, _1, "Face creation failed"));
+  }
+  else
+    throw Error("invalid uri format");
+}
+ 
+void
+Controller::faceDestroy(const char* commandOptions[])
+{
+  ndn::nfd::FaceManagementOptions faceOptions;
+  const int faceId = boost::lexical_cast<int>(commandOptions[0]);
+  faceOptions.setFaceId(faceId);
+                        
+  startFaceCommand("destroy",
+                   faceOptions,
+                   bind(&Controller::onFaceSuccess, this, _1, "Face destroy succeeded"),
+                   bind(&Controller::onError, this, _1, "Face destroy failed"));
+}
+
+void
+Controller::onFibSuccess(const ndn::nfd::FibManagementOptions& resp, const std::string& message)
+{
+  std::cout << resp << std::endl;
+}
+  
+void
+Controller::onFaceSuccess(const ndn::nfd::FaceManagementOptions& resp, const std::string& message)
+{
+  std::cout << resp << std::endl;
+}
+  
+void
+Controller::onError(const std::string& error, const std::string& message)
+{
+  throw Error(message + ": " + error);
+}
+}// namespace nfdc
+
+int
+main(int argc, char** argv)
+{
+  ndn::Face face;
+  nfdc::Controller p(face);
+  
+  p.m_programName = argv[0];
+  int opt;
+  while ((opt = getopt(argc, argv, "h")) != -1) {
+    switch (opt) {
+      case 'h':
+        usage(p.m_programName);
+        return 0;
+        
+      default:
+        usage(p.m_programName);
+        return 1;
+    }
+  }
+  try {
+    bool hasSucceeded = p.dispatch(argv[optind],
+                                   const_cast<const char**>(argv + optind + 1),
+                                   argc - optind - 1);
+    if (hasSucceeded == false) {
+      usage(p.m_programName);
+      return 1;
+    }
+    
+    face.processEvents();
+  }
+  catch (const std::exception& e) {
+    std::cerr << "ERROR: " << e.what() << std::endl;
+    return 2;
+  }
+  return 0;
+}
+