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;
+}
+