nrd: Basic version of nrd
refs #1324
Change-Id: I797922e8367e0473bb8ed39840e44d038295f148
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