nrd: Basic version of nrd
refs #1324
Change-Id: I797922e8367e0473bb8ed39840e44d038295f148
diff --git a/src/common.hpp b/src/common.hpp
index e19ead0..b09fc63 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -10,6 +10,18 @@
#include <iostream>
#include <list>
+#include <ndn-cpp-dev/face.hpp>
+#include <ndn-cpp-dev/security/key-chain.hpp>
+#include <ndn-cpp-dev/util/scheduler.hpp>
+
+#include <ndn-cpp-dev/management/nfd-fib-management-options.hpp>
+#include <ndn-cpp-dev/management/nfd-face-management-options.hpp>
+#include <ndn-cpp-dev/management/nfd-controller.hpp>
+#include <ndn-cpp-dev/management/nfd-control-response.hpp>
#include <ndn-cpp-dev/management/nrd-prefix-reg-options.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/regex_find_format.hpp>
+
#endif // NRD_COMMON_HPP
diff --git a/src/main.cpp b/src/main.cpp
index 0ec8e7a..ce89f3f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4,8 +4,18 @@
* See COPYING for copyright and distribution information.
*/
+#include "nrd.hpp"
+
int
main(int argc, char** argv)
{
+ try {
+ ndn::nrd::Nrd nrd;
+ nrd.enableLocalControlHeader();
+ nrd.listen();
+ }
+ catch (std::exception& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ }
return 0;
}
diff --git a/src/nrd.cpp b/src/nrd.cpp
new file mode 100644
index 0000000..0928a63
--- /dev/null
+++ b/src/nrd.cpp
@@ -0,0 +1,260 @@
+/* -*- 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 "nrd.hpp"
+
+namespace ndn {
+namespace nrd {
+
+const Name Nrd::COMMAND_PREFIX = "/localhost/nrd";
+
+const size_t Nrd::COMMAND_UNSIGNED_NCOMPS =
+ Nrd::COMMAND_PREFIX.size() +
+ 1 + // verb
+ 1; // verb options
+
+const size_t Nrd::COMMAND_SIGNED_NCOMPS =
+ Nrd::COMMAND_UNSIGNED_NCOMPS +
+ 4; // (timestamp, nonce, signed info tlv, signature tlv)
+
+const Nrd::VerbAndProcessor Nrd::COMMAND_VERBS[] =
+ {
+ VerbAndProcessor(
+ Name::Component("register"),
+ &Nrd::insertEntry
+ ),
+
+ VerbAndProcessor(
+ Name::Component("unregister"),
+ &Nrd::deleteEntry
+ ),
+ };
+
+void
+setInterestFilterFailed(const Name& name, const std::string& msg)
+{
+ std::cerr << "Error in setting interest filter (" << name << "): " << msg << std::endl;
+}
+
+Nrd::Nrd()
+ : m_nfdController(new nfd::Controller(m_face)),
+ m_verbDispatch(COMMAND_VERBS,
+ COMMAND_VERBS + (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor)))
+{
+ m_face.setController(m_nfdController);
+ m_face.setInterestFilter("/localhost/nrd",
+ bind(&Nrd::onRibRequest, this, _2),
+ bind(&setInterestFilterFailed, _1, _2));
+}
+
+void
+Nrd::sendResponse(const Name& name,
+ const nfd::ControlResponse& response)
+{
+ const Block& encodedControl = response.wireEncode();
+
+ Data responseData(name);
+ responseData.setContent(encodedControl);
+
+ m_keyChain.sign(responseData);
+ m_face.put(responseData);
+}
+
+void
+Nrd::sendResponse(const Name& name,
+ uint32_t code,
+ const std::string& text)
+{
+ nfd::ControlResponse response(code, text);
+ sendResponse(name, response);
+}
+
+void
+Nrd::onRibRequest(const Interest& request)
+{
+ const Name& command = request.getName();
+ const size_t commandNComps = command.size();
+
+ if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
+ commandNComps < COMMAND_SIGNED_NCOMPS)
+ {
+ std::cerr << "Error: Signature required" << std::endl;
+ sendResponse(command, 401, "Signature required");
+ return;
+ }
+ else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
+ !COMMAND_PREFIX.isPrefixOf(command))
+ {
+ std::cerr << "Error: Malformed Command" << std::endl;
+ sendResponse(command, 400, "Malformed command");
+ return;
+ }
+
+ const Name::Component& verb = command.get(COMMAND_PREFIX.size());
+ VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find(verb);
+
+ if (verbProcessor != m_verbDispatch.end())
+ {
+ PrefixRegOptions options;
+ if (!extractOptions(request, options))
+ {
+ sendResponse(command, 400, "Malformed command");
+ return;
+ }
+
+ /// \todo authorize command
+ if (false)
+ {
+ sendResponse(request.getName(), 403, "Unauthorized command");
+ return;
+ }
+
+ // \todo add proper log support
+ std::cout << "Received options (name, faceid, cost): " << options.getName() <<
+ ", " << options.getFaceId() << ", " << options.getCost() << std::endl;
+
+ nfd::ControlResponse response;
+ (verbProcessor->second)(this, request, options);
+ }
+ else
+ {
+ sendResponse(request.getName(), 501, "Unsupported command");
+ }
+}
+
+bool
+Nrd::extractOptions(const Interest& request,
+ PrefixRegOptions& 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)
+ {
+ return false;
+ }
+
+ if (extractedOptions.getFaceId() == 0)
+ {
+ std::cout <<"IncomingFaceId: " << request.getIncomingFaceId() << std::endl;
+ extractedOptions.setFaceId(request.getIncomingFaceId());
+ }
+ return true;
+}
+
+void
+Nrd::onCommandError(const std::string& error,
+ const Interest& request,
+ const PrefixRegOptions& options)
+{
+ nfd::ControlResponse response;
+
+ response.setCode(400);
+ response.setText(error);
+
+ std::cout << "Error: " << error << std::endl;
+ sendResponse(request.getName(), response);
+ m_managedRib.erase(options);
+}
+
+void
+Nrd::onUnRegSuccess(const Interest& request, const PrefixRegOptions& options)
+{
+ nfd::ControlResponse response;
+
+ response.setCode(200);
+ response.setText("Success");
+ response.setBody(options.wireEncode());
+
+ std::cout << "Success: Name unregistered (" <<
+ options.getName() << ", " <<
+ options.getFaceId() << ")" << std::endl;
+ sendResponse(request.getName(), response);
+ m_managedRib.erase(options);
+}
+
+void
+Nrd::onRegSuccess(const Interest& request, const PrefixRegOptions& options)
+{
+ nfd::ControlResponse response;
+
+ response.setCode(200);
+ response.setText("Success");
+ response.setBody(options.wireEncode());
+
+ std::cout << "Success: Name registered (" << options.getName() << ", " <<
+ options.getFaceId() << ")" << std::endl;
+ sendResponse(request.getName(), response);
+}
+
+
+void
+Nrd::insertEntry(const Interest& request, const PrefixRegOptions& options)
+{
+ // For right now, just pass the options to fib as it is,
+ // without processing flags. Later options will be first added to
+ // Rib tree, then nrd will generate fib updates based on flags and then
+ // will add next hops one by one..
+ m_managedRib.insert(options);
+ m_nfdController->fibAddNextHop(options.getName(), options.getFaceId(),
+ options.getCost(),
+ bind(&Nrd::onRegSuccess, this, request, options),
+ bind(&Nrd::onCommandError, this, _1, request, options));
+}
+
+
+void
+Nrd::deleteEntry(const Interest& request, const PrefixRegOptions& options)
+{
+ m_nfdController->fibRemoveNextHop(options.getName(),
+ options.getFaceId(),
+ bind(&Nrd::onUnRegSuccess, this, request, options),
+ bind(&Nrd::onCommandError, this, _1, request, options));
+}
+
+
+void
+Nrd::listen()
+{
+ std::cout << "NRD started: listening for incoming interests" << std::endl;
+ m_face.processEvents();
+}
+
+
+void
+Nrd::onControlHeaderSuccess()
+{
+ std::cout << "Local control header enabled" << std::endl;
+}
+
+
+void
+Nrd::onControlHeaderError()
+{
+ std::cout << "Error: couldn't enable local control header" << std::endl;
+ m_face.shutdown();
+}
+
+
+void
+Nrd::enableLocalControlHeader()
+{
+ Name enable("/localhost/nfd/control-header/in-faceid/enable");
+ Interest enableCommand(enable);
+
+ m_keyChain.sign(enableCommand);
+ m_face.expressInterest(enableCommand,
+ ndn::bind(&Nrd::onControlHeaderSuccess, this),
+ ndn::bind(&Nrd::onControlHeaderError, this));
+}
+
+} // namespace nrd
+} // namespace ndn
diff --git a/src/nrd.hpp b/src/nrd.hpp
new file mode 100644
index 0000000..210af74
--- /dev/null
+++ b/src/nrd.hpp
@@ -0,0 +1,98 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NRD_HPP
+#define NRD_HPP
+
+#include "rib.hpp"
+
+namespace ndn {
+namespace nrd {
+
+class Nrd
+{
+public:
+ Nrd();
+
+ void
+ onRibRequest(const Interest& request);
+
+ void
+ enableLocalControlHeader();
+
+ void
+ listen();
+
+private:
+ void
+ sendResponse(const Name& name,
+ const nfd::ControlResponse& response);
+
+ void
+ sendResponse(const Name& name,
+ uint32_t code,
+ const std::string& text);
+ void
+ onCommandError(const std::string& error,
+ const ndn::Interest& interest,
+ const PrefixRegOptions& options);
+
+ void
+ onRegSuccess(const ndn::Interest& interest, const PrefixRegOptions& options);
+
+ void
+ onUnRegSuccess(const ndn::Interest& interest, const PrefixRegOptions& options);
+
+ void
+ onControlHeaderSuccess();
+
+ void
+ onControlHeaderError();
+
+ void
+ insertEntry(const Interest& request, const PrefixRegOptions& options);
+
+ void
+ deleteEntry(const Interest& request, const PrefixRegOptions& options);
+
+ bool
+ extractOptions(const Interest& request,
+ PrefixRegOptions& extractedOptions);
+private:
+ Rib m_managedRib;
+ ndn::Face m_face;
+ ndn::KeyChain m_keyChain;
+ shared_ptr<nfd::Controller> m_nfdController;
+
+ typedef boost::function<void(Nrd*,
+ const Interest&,
+ const PrefixRegOptions&)> VerbProcessor;
+
+ typedef std::map<Name::Component, VerbProcessor> VerbDispatchTable;
+
+ typedef std::pair<Name::Component, VerbProcessor> VerbAndProcessor;
+
+
+ const VerbDispatchTable m_verbDispatch;
+
+ static const Name COMMAND_PREFIX; // /localhost/nrd
+
+ // number of components in an invalid, but not malformed, unsigned command.
+ // (/localhost/nrd + verb + options) = 4
+ static const size_t COMMAND_UNSIGNED_NCOMPS;
+
+ // number of components in a valid signed Interest.
+ // 5 in mock (see UNSIGNED_NCOMPS), 8 with signed Interest support.
+ static const size_t COMMAND_SIGNED_NCOMPS;
+
+ static const VerbAndProcessor COMMAND_VERBS[];
+};
+
+} // namespace nrd
+} // namespace ndn
+
+#endif // NRD_HPP
+
diff --git a/src/rib.cpp b/src/rib.cpp
index 0e0cbfe..3fc9399 100644
--- a/src/rib.cpp
+++ b/src/rib.cpp
@@ -13,7 +13,7 @@
{
}
-//
+
Rib::~Rib()
{
}
@@ -24,7 +24,7 @@
return opt1.getName() == opt2.getName();
}
-//
+
Rib::const_iterator
Rib::find(const PrefixRegOptions& options) const
{
@@ -38,7 +38,7 @@
return it;
}
-//
+
void
Rib::insert(const PrefixRegOptions& options)
{
@@ -50,7 +50,7 @@
}
}
-//
+
void
Rib::erase(const PrefixRegOptions& options)
{