face: Implementing nfd::Controller

This commit also adds an option for Node constructor to use
nfd::Controller instead of default ndnd::Controller to set interest
filter (register prefix).

Change-Id: If395756c1b98abe909cec0967c07d347affe5928
diff --git a/src/management/ndnd-controller.cpp b/src/management/ndnd-controller.cpp
new file mode 100644
index 0000000..e95d85e
--- /dev/null
+++ b/src/management/ndnd-controller.cpp
@@ -0,0 +1,266 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "common.hpp"
+#include "ndnd-controller.hpp"
+
+#include "../node.hpp"
+#include "../security/signature-sha256-with-rsa.hpp"
+#include "../util/random.hpp"
+
+#include "ndnd-forwarding-entry.hpp"
+#include "ndnd-face-instance.hpp"
+#include "ndnd-status-response.hpp"
+
+namespace ndn {
+namespace ndnd {
+
+Controller::Controller(Node& face)
+  : m_face(face)
+  , m_faceId(-1)
+{
+}
+
+void
+Controller::selfRegisterPrefix(const Name& prefixToRegister,
+                               const SuccessCallback& onSuccess,
+                               const FailCallback&    onFail)
+{
+  if (!m_ndndId.hasValue())
+    {
+      if (m_filterRequests.empty())
+        {
+          m_face.expressInterest(Name("/%C1.M.S.localhost/%C1.M.SRV/ndnd/KEY"),
+                                 bind(&Controller::onNdnidFetched, this, _1, _2),
+                                 bind(onFail, "NDNDID fetching timed out"));
+        }
+      m_filterRequests.push_back(FilterRequest(prefixToRegister, onSuccess, onFail));
+    }
+  else
+    startPrefixAction(ForwardingEntry("selfreg", prefixToRegister),
+                      bind(&Controller::recordSelfRegisteredFaceId, this, _1, onSuccess),
+                      onFail);
+}
+
+
+void
+Controller::selfDeregisterPrefix(const Name& prefixToRegister,
+                                 const SuccessCallback& onSuccess,
+                                 const FailCallback&    onFail)
+{
+  if (!m_ndndId.hasValue() || m_faceId == -1)
+    {
+      if (static_cast<bool>(onFail))
+        onFail("NDNID is not available (must have been present after a successful registration operation)");
+      return;
+    }
+
+  startPrefixAction(ForwardingEntry("unreg", prefixToRegister, m_faceId),
+                    bind(onSuccess), onFail);
+}
+
+
+void 
+Controller::onNdnidFetched(const shared_ptr<const Interest>& interest,
+                           const shared_ptr<Data>& data)
+{
+  if (data->getName().size() > interest->getName().size())
+    {
+      m_ndndId = data->getName()[interest->getName().size()];
+
+      for (FilterRequestList::iterator i = m_filterRequests.begin();
+           i != m_filterRequests.end();
+           ++i)
+        {
+          startPrefixAction(ForwardingEntry("selfreg", i->m_prefixToRegister),
+                            bind(&Controller::recordSelfRegisteredFaceId, this, _1, i->m_onSuccess),
+                            i->m_onFailure);
+        }
+    }
+  else
+    {
+      for (FilterRequestList::iterator i = m_filterRequests.begin();
+           i != m_filterRequests.end();
+           ++i)
+        {
+          if (static_cast<bool>(i->m_onFailure))
+              i->m_onFailure("NDNID cannot be fetched");
+        }
+    }
+  m_filterRequests.clear();
+}
+
+void
+Controller::recordSelfRegisteredFaceId(const ForwardingEntry& entry,
+                                       const SuccessCallback& onSuccess)
+{
+  m_faceId = entry.getFaceId();
+  if (static_cast<bool>(onSuccess))
+    onSuccess();
+}
+
+void
+Controller::startFaceAction(const FaceInstance& entry,
+                            const FaceOperationSucceedCallback& onSuccess,
+                            const FailCallback& onFail)
+{
+  // Set the ForwardingEntry as the content of a Data packet and sign.
+  Data data;
+  data.setName(Name().appendVersion(ndn::random::generateWord32()));
+  data.setContent(entry.wireEncode());
+  
+  // Create an empty signature, since nobody going to verify it for now
+  // @todo In the future, we may require real signatures to do the registration
+  SignatureSha256WithRsa signature;
+  signature.setValue(Block(Tlv::SignatureValue));
+  data.setSignature(signature);
+
+  // Create an interest where the name has the encoded Data packet.
+  Name interestName;
+  interestName.append("ndnx");
+  interestName.append(m_ndndId);
+  interestName.append(entry.getAction());
+  interestName.append(data.wireEncode());
+
+  Interest interest(interestName);
+  interest.setScope(1);
+  interest.setInterestLifetime(1000);
+  interest.setMustBeFresh(true);
+
+  m_face.expressInterest(interest,
+                         bind(&Controller::processFaceActionResponse, this, _2, onSuccess, onFail),
+                         bind(onFail, "Command Interest failed"));
+}
+
+void
+Controller::startPrefixAction(const ForwardingEntry& entry,
+                              const PrefixOperationSucceedCallback& onSuccess,
+                              const FailCallback& onFail)
+{
+  // Set the ForwardingEntry as the content of a Data packet and sign.
+  Data data;
+  data.setName(Name().appendVersion(random::generateWord32()));
+  data.setContent(entry.wireEncode());
+  
+  // Create an empty signature, since nobody going to verify it for now
+  // @todo In the future, we may require real signatures to do the registration
+  SignatureSha256WithRsa signature;
+  signature.setValue(Block(Tlv::SignatureValue));
+  data.setSignature(signature);
+
+  // Create an interest where the name has the encoded Data packet.
+  Name interestName;
+  interestName.append("ndnx");
+  interestName.append(m_ndndId);
+  interestName.append(entry.getAction());
+  interestName.append(data.wireEncode());
+
+  Interest interest(interestName);
+  interest.setScope(1);
+  interest.setInterestLifetime(1000);
+  interest.setMustBeFresh(true);
+
+  m_face.expressInterest(interest,
+                         bind(&Controller::processPrefixActionResponse, this, _2, onSuccess, onFail),
+                         bind(onFail, "Command Interest timed out"));
+}
+
+void
+Controller::processFaceActionResponse(const shared_ptr<Data>& data,
+                                      const FaceOperationSucceedCallback& onSuccess,
+                                      const FailCallback& onFail)
+{
+  Block content = data->getContent();
+  content.parse();
+
+  if (content.getAll().empty())
+    {
+      if (static_cast<bool>(onFail))
+        onFail("Empty response");
+      return;
+    }
+
+  Block::element_iterator val = content.getAll().begin();
+  
+  switch(val->type())
+    {
+    case Tlv::FaceManagement::FaceInstance:
+      {
+        FaceInstance entry;
+        entry.wireDecode(*val);
+
+        if (static_cast<bool>(onSuccess))
+          onSuccess(entry);
+        return;
+      }
+    case Tlv::FaceManagement::StatusResponse:
+      {
+        StatusResponse resp;
+        resp.wireDecode(*val);
+
+        if (static_cast<bool>(onFail))
+          onFail(resp.getInfo());
+        return;
+      }
+    default:
+      {
+        if (static_cast<bool>(onFail))
+          onFail("Invalid response");
+        return;
+      }
+    }
+}
+
+void
+Controller::processPrefixActionResponse(const shared_ptr<Data>& data,
+                                        const PrefixOperationSucceedCallback& onSuccess,
+                                        const FailCallback& onFail)
+{
+  Block content = data->getContent();
+  content.parse();
+
+  if (content.getAll().empty())
+    {
+      if (static_cast<bool>(onFail))
+        onFail("Empty response");
+      return;
+    }
+
+  Block::element_iterator val = content.getAll().begin();
+  
+  switch(val->type())
+    {
+    case Tlv::FaceManagement::ForwardingEntry:
+      {
+        ForwardingEntry entry;
+        entry.wireDecode(*val);
+
+        if (static_cast<bool>(onSuccess))
+          onSuccess(entry);
+        return;
+      }
+    case Tlv::FaceManagement::StatusResponse:
+      {
+        StatusResponse resp;
+        resp.wireDecode(*val);
+
+        // std::cerr << "StatusReponse: " << resp << std::endl;
+      
+        if (static_cast<bool>(onFail))
+          onFail(resp.getInfo());
+        return;
+      }
+    default:
+      {
+        if (static_cast<bool>(onFail))
+          onFail("Invalid response");
+        return;
+      }
+    }
+}
+
+} // namespace ndnd
+} // namespace ndn