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/controller.hpp b/src/management/controller.hpp
new file mode 100644
index 0000000..f919489
--- /dev/null
+++ b/src/management/controller.hpp
@@ -0,0 +1,43 @@
+/* -*- 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.
+ */
+
+#ifndef NDN_MANAGEMENT_CONTROLLER_HPP
+#define NDN_MANAGEMENT_CONTROLLER_HPP
+
+#include "../common.hpp"
+#include "../name.hpp"
+#include "../interest.hpp"
+#include "../data.hpp"
+
+namespace ndn {
+
+class Node;
+
+class Controller
+{
+public:
+  typedef function<void()>                   SuccessCallback;
+  typedef function<void(const std::string&)> FailCallback;
+
+  virtual
+  ~Controller()
+  {
+  }
+  
+  virtual void
+  selfRegisterPrefix(const Name& prefixToRegister,
+                     const SuccessCallback& onSuccess,
+                     const FailCallback&    onFail) = 0;
+
+  virtual void
+  selfDeregisterPrefix(const Name& prefixToRegister,
+                       const SuccessCallback& onSuccess,
+                       const FailCallback&    onFail) = 0;
+};
+
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_CONTROLLER_HPP
diff --git a/src/management/ndnd-control.cpp b/src/management/ndnd-controller.cpp
similarity index 66%
rename from src/management/ndnd-control.cpp
rename to src/management/ndnd-controller.cpp
index 6f48231..e95d85e 100644
--- a/src/management/ndnd-control.cpp
+++ b/src/management/ndnd-controller.cpp
@@ -5,6 +5,8 @@
  */
 
 #include "common.hpp"
+#include "ndnd-controller.hpp"
+
 #include "../node.hpp"
 #include "../security/signature-sha256-with-rsa.hpp"
 #include "../util/random.hpp"
@@ -16,43 +18,43 @@
 namespace ndn {
 namespace ndnd {
 
-Control::Control(Node& face)
+Controller::Controller(Node& face)
   : m_face(face)
   , m_faceId(-1)
 {
 }
 
 void
-Control::selfRegisterPrefix(const Name& prefixToRegister,
-                            const SuccessCallback& onSuccess,
-                            const FailCallback&    onFail)
+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(&Control::onNdnidFetched, this, _1, _2),
-                                 bind(onFail));
+                                 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(&Control::recordSelfRegisteredFaceId, this, _1, onSuccess),
+                      bind(&Controller::recordSelfRegisteredFaceId, this, _1, onSuccess),
                       onFail);
 }
 
 
 void
-Control::selfDeregisterPrefix(const Name& prefixToRegister,
-                              const SuccessCallback& onSuccess,
-                              const FailCallback&    onFail)
+Controller::selfDeregisterPrefix(const Name& prefixToRegister,
+                                 const SuccessCallback& onSuccess,
+                                 const FailCallback&    onFail)
 {
   if (!m_ndndId.hasValue() || m_faceId == -1)
     {
       if (static_cast<bool>(onFail))
-        onFail();
+        onFail("NDNID is not available (must have been present after a successful registration operation)");
       return;
     }
 
@@ -62,8 +64,8 @@
 
 
 void 
-Control::onNdnidFetched(const shared_ptr<const Interest>& interest,
-                        const shared_ptr<Data>& data)
+Controller::onNdnidFetched(const shared_ptr<const Interest>& interest,
+                           const shared_ptr<Data>& data)
 {
   if (data->getName().size() > interest->getName().size())
     {
@@ -74,7 +76,7 @@
            ++i)
         {
           startPrefixAction(ForwardingEntry("selfreg", i->m_prefixToRegister),
-                            bind(&Control::recordSelfRegisteredFaceId, this, _1, i->m_onSuccess),
+                            bind(&Controller::recordSelfRegisteredFaceId, this, _1, i->m_onSuccess),
                             i->m_onFailure);
         }
     }
@@ -85,15 +87,15 @@
            ++i)
         {
           if (static_cast<bool>(i->m_onFailure))
-              i->m_onFailure();
+              i->m_onFailure("NDNID cannot be fetched");
         }
     }
   m_filterRequests.clear();
 }
 
 void
-Control::recordSelfRegisteredFaceId(const ForwardingEntry& entry,
-                                    const SuccessCallback& onSuccess)
+Controller::recordSelfRegisteredFaceId(const ForwardingEntry& entry,
+                                       const SuccessCallback& onSuccess)
 {
   m_faceId = entry.getFaceId();
   if (static_cast<bool>(onSuccess))
@@ -101,9 +103,9 @@
 }
 
 void
-Control::startFaceAction(const FaceInstance& entry,
-                         const FaceOperationSucceedCallback& onSuccess,
-                         const FailCallback& onFailure)
+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;
@@ -129,14 +131,14 @@
   interest.setMustBeFresh(true);
 
   m_face.expressInterest(interest,
-                         bind(&Control::processFaceActionResponse, this, _2, onSuccess, onFailure),
-                         bind(onFailure));
+                         bind(&Controller::processFaceActionResponse, this, _2, onSuccess, onFail),
+                         bind(onFail, "Command Interest failed"));
 }
 
 void
-Control::startPrefixAction(const ForwardingEntry& entry,
-                           const PrefixOperationSucceedCallback& onSuccess,
-                           const FailCallback& onFailure)
+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;
@@ -162,14 +164,14 @@
   interest.setMustBeFresh(true);
 
   m_face.expressInterest(interest,
-                         bind(&Control::processPrefixActionResponse, this, _2, onSuccess, onFailure),
-                         bind(onFailure));
+                         bind(&Controller::processPrefixActionResponse, this, _2, onSuccess, onFail),
+                         bind(onFail, "Command Interest timed out"));
 }
 
 void
-Control::processFaceActionResponse(const shared_ptr<Data>& data,
-                                   const FaceOperationSucceedCallback& onSuccess,
-                                   const FailCallback& onFail)
+Controller::processFaceActionResponse(const shared_ptr<Data>& data,
+                                      const FaceOperationSucceedCallback& onSuccess,
+                                      const FailCallback& onFail)
 {
   Block content = data->getContent();
   content.parse();
@@ -177,7 +179,7 @@
   if (content.getAll().empty())
     {
       if (static_cast<bool>(onFail))
-        onFail();
+        onFail("Empty response");
       return;
     }
 
@@ -200,22 +202,22 @@
         resp.wireDecode(*val);
 
         if (static_cast<bool>(onFail))
-          onFail();
+          onFail(resp.getInfo());
         return;
       }
     default:
       {
         if (static_cast<bool>(onFail))
-          onFail();
+          onFail("Invalid response");
         return;
       }
     }
 }
 
 void
-Control::processPrefixActionResponse(const shared_ptr<Data>& data,
-                                     const PrefixOperationSucceedCallback& onSuccess,
-                                     const FailCallback& onFail)
+Controller::processPrefixActionResponse(const shared_ptr<Data>& data,
+                                        const PrefixOperationSucceedCallback& onSuccess,
+                                        const FailCallback& onFail)
 {
   Block content = data->getContent();
   content.parse();
@@ -223,7 +225,7 @@
   if (content.getAll().empty())
     {
       if (static_cast<bool>(onFail))
-        onFail();
+        onFail("Empty response");
       return;
     }
 
@@ -248,13 +250,13 @@
         // std::cerr << "StatusReponse: " << resp << std::endl;
       
         if (static_cast<bool>(onFail))
-          onFail();
+          onFail(resp.getInfo());
         return;
       }
     default:
       {
         if (static_cast<bool>(onFail))
-          onFail();
+          onFail("Invalid response");
         return;
       }
     }
diff --git a/src/management/ndnd-control.hpp b/src/management/ndnd-controller.hpp
similarity index 88%
rename from src/management/ndnd-control.hpp
rename to src/management/ndnd-controller.hpp
index fd22f15..319f995 100644
--- a/src/management/ndnd-control.hpp
+++ b/src/management/ndnd-controller.hpp
@@ -4,10 +4,15 @@
  * See COPYING for copyright and distribution information.
  */
 
-#ifndef NDN_MANAGEMENT_NDND_CONTROL_HPP
-#define NDN_MANAGEMENT_NDND_CONTROL_HPP
+#ifndef NDN_MANAGEMENT_NDND_CONTROLLER_HPP
+#define NDN_MANAGEMENT_NDND_CONTROLLER_HPP
 
 #include "../common.hpp"
+#include "controller.hpp"
+
+#include "../name.hpp"
+#include "../interest.hpp"
+#include "../data.hpp"
 
 namespace ndn {
 
@@ -23,26 +28,23 @@
  *
  * ndnd::Control should be used when connecting to ndnd-tlv daemon
  */
-class Control
+class Controller : public ndn::Controller
 {
 public:
-  typedef function<void()>                       SuccessCallback;
-  typedef function<void()>                       FailCallback;
-
   typedef function<void(const ForwardingEntry&)> PrefixOperationSucceedCallback;
   typedef function<void(const FaceInstance&)>    FaceOperationSucceedCallback;
 
   /**
    * @brief Construct ndnd::Control object
    */
-  Control(Node& face);
+  Controller(Node& face);
 
-  void
+  virtual void
   selfRegisterPrefix(const Name& prefixToRegister,
                      const SuccessCallback& onSuccess,
                      const FailCallback&    onFail);
 
-  void
+  virtual void
   selfDeregisterPrefix(const Name& prefixToRegister,
                        const SuccessCallback& onSuccess,
                        const FailCallback&    onFail);
@@ -106,4 +108,4 @@
 } // namespace ndnd
 } // namespace ndn
 
-#endif // NDN_MANAGEMENT_NDND_CONTROL_HPP
+#endif // NDN_MANAGEMENT_NDND_CONTROLLER_HPP
diff --git a/src/management/control-response.hpp b/src/management/nfd-control-response.hpp
similarity index 92%
rename from src/management/control-response.hpp
rename to src/management/nfd-control-response.hpp
index f493f5a..238d1c5 100644
--- a/src/management/control-response.hpp
+++ b/src/management/nfd-control-response.hpp
@@ -11,6 +11,7 @@
 #include "../encoding/tlv-nfd-control.hpp"
 
 namespace ndn {
+namespace nfd {
 
 /**
  * @brief Class defining abstraction of ControlResponse for NFD Control Protocol
@@ -31,6 +32,11 @@
     , m_text(text)
   {
   }
+
+  ControlResponse(const Block& block)
+  {
+    wireDecode(block);
+  }
   
   inline uint32_t
   getCode() const;
@@ -133,6 +139,9 @@
   m_wire = wire;
   m_wire.parse();
 
+  if (m_wire.type() != tlv::nfd_control::ControlResponse)
+    throw Error("Requested decoding of ControlResponse, but Block is of different type");  
+  
   Block::element_iterator val = m_wire.getAll().begin();
   if (val == m_wire.getAll().end() ||
       val->type() != tlv::nfd_control::StatusCode)
@@ -164,6 +173,7 @@
   return os;
 }
 
+} // namespace nfd
 } // namespace ndn
 
 #endif // NDN_MANAGEMENT_CONTROL_RESPONSE_HPP
diff --git a/src/management/nfd-control.hpp b/src/management/nfd-control.hpp
deleted file mode 100644
index 642afd8..0000000
--- a/src/management/nfd-control.hpp
+++ /dev/null
@@ -1,14 +0,0 @@
-/* -*- 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.
- */
-
-#ifndef NDN_MANAGEMENT_NFD_CONTROL_HPP
-#define NDN_MANAGEMENT_NFD_CONTROL_HPP
-
-namespace ndn {
-
-} // namespace ndn
-
-#endif // NDN_MANAGEMENT_NFD_CONTROL_HPP
diff --git a/src/management/nfd-controller.cpp b/src/management/nfd-controller.cpp
new file mode 100644
index 0000000..c72c5d3
--- /dev/null
+++ b/src/management/nfd-controller.cpp
@@ -0,0 +1,122 @@
+/* -*- 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 "../node.hpp"
+
+#include "nfd-controller.hpp"
+#include "nfd-fib-management-options.hpp"
+#include "nfd-control-response.hpp"
+
+namespace ndn {
+namespace nfd {
+
+Controller::Controller(Node& face)
+  : m_face(face)
+  , m_faceId(0)
+{
+}
+
+void
+Controller::selfRegisterPrefix(const Name& prefixToRegister,
+                               const SuccessCallback& onSuccess,
+                               const FailCallback&    onFail)
+{
+  startFibCommand("add-nexthop",
+                  FibManagementOptions()
+                  .setName(prefixToRegister)
+                  .setFaceId(0) // self-registration
+                  .setCost(0),
+                  bind(&Controller::recordSelfRegisteredFaceId, this, _1, onSuccess),
+                  onFail);
+}
+
+void
+Controller::selfDeregisterPrefix(const Name& prefixToRegister,
+                                 const SuccessCallback& onSuccess,
+                                 const FailCallback&    onFail)
+{
+  if (m_faceId == 0)
+    {
+      if (static_cast<bool>(onFail))
+        onFail("Face ID is not set, should have been set after a successful prefix registration command");
+      return;
+    }
+  
+  startFibCommand("remove-nexthop",
+                  FibManagementOptions()
+                  .setName(prefixToRegister)
+                  .setFaceId(m_faceId),
+                  bind(onSuccess), onFail);
+}
+
+void
+Controller::startFibCommand(const std::string& command,
+                            const FibManagementOptions& options,
+                            const FibCommandSucceedCallback& onSuccess,
+                            const FailCallback& onFail)
+{
+  Name fibCommandInterestName("/localhost/nfd/fib");
+  fibCommandInterestName
+    .append(command)
+    .append(options.wireEncode());
+
+  Interest fibCommandInterest(fibCommandInterestName);
+  m_keyChain.sign(fibCommandInterest);
+
+  m_face.expressInterest(fibCommandInterest,
+                         bind(&Controller::processFibCommandResponse, this, _2,
+                              onSuccess, onFail),
+                         bind(onFail, "Command Interest timed out"));
+}
+
+void
+Controller::recordSelfRegisteredFaceId(const FibManagementOptions& entry,
+                                       const SuccessCallback& onSuccess)
+{
+  m_faceId = entry.getFaceId();
+  onSuccess();
+}
+
+// void
+// processFaceActionResponse(const shared_ptr<Data>& data,
+//                           const FaceOperationSucceedCallback& onSuccess,
+//                           const FailCallback&    onFail);
+
+void
+Controller::processFibCommandResponse(const shared_ptr<Data>& data,
+                                      const FibCommandSucceedCallback& onSuccess,
+                                      const FailCallback& onFail)
+{
+  try
+    {
+      ControlResponse response(data->getContent().blockFromValue());
+
+      if (response.getCode() != 200)
+        return onFail(response.getText());
+
+      FibManagementOptions options(response.getBody());
+      return onSuccess(options);
+    }
+  catch(ndn::Tlv::Error& e)
+    {
+      if (static_cast<bool>(onFail))
+        return onFail(e.what());
+    }
+  catch(ControlResponse::Error& e)
+    {
+      if (static_cast<bool>(onFail))
+        return onFail(e.what());
+    }
+  catch(FibManagementOptions::Error& e)
+    {
+      if (static_cast<bool>(onFail))
+        return onFail(e.what());
+    }
+}
+
+} // namespace nfd
+} // namespace ndn
diff --git a/src/management/nfd-controller.hpp b/src/management/nfd-controller.hpp
new file mode 100644
index 0000000..d5400c6
--- /dev/null
+++ b/src/management/nfd-controller.hpp
@@ -0,0 +1,75 @@
+/* -*- 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.
+ */
+
+#ifndef NDN_MANAGEMENT_NFD_CONTROL_HPP
+#define NDN_MANAGEMENT_NFD_CONTROL_HPP
+
+#include "../common.hpp"
+#include "controller.hpp"
+
+#include "../name.hpp"
+#include "../interest.hpp"
+#include "../data.hpp"
+#include "../security/key-chain.hpp"
+
+namespace ndn {
+
+class Name;
+
+namespace nfd {
+
+class FibManagementOptions;
+
+class Controller : public ndn::Controller
+{
+public:
+  typedef function<void(const FibManagementOptions&)> FibCommandSucceedCallback;
+
+  /**
+   * @brief Construct ndnd::Control object
+   */
+  Controller(Node& face);
+
+  virtual void
+  selfRegisterPrefix(const Name& prefixToRegister,
+                     const SuccessCallback& onSuccess,
+                     const FailCallback&    onFail);
+
+  virtual void
+  selfDeregisterPrefix(const Name& prefixToRegister,
+                       const SuccessCallback& onSuccess,
+                       const FailCallback&    onFail);
+
+  void
+  startFibCommand(const std::string& command,
+                  const FibManagementOptions& options,
+                  const FibCommandSucceedCallback& onSuccess,
+                  const FailCallback& onFailure);
+private:
+  void
+  recordSelfRegisteredFaceId(const FibManagementOptions& entry,
+                             const SuccessCallback& onSuccess);
+
+  // void
+  // processFaceActionResponse(const shared_ptr<Data>& data,
+  //                           const FaceOperationSucceedCallback& onSuccess,
+  //                           const FailCallback&    onFail);
+
+  void
+  processFibCommandResponse(const shared_ptr<Data>& data,
+                            const FibCommandSucceedCallback& onSuccess,
+                            const FailCallback& onFail);
+  
+private:
+  Node& m_face;
+  KeyChain m_keyChain;
+  uint64_t m_faceId; // internal face ID (needed for prefix de-registration)
+};
+
+} // namespace nfd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NFD_CONTROL_HPP
diff --git a/src/management/fib-management-options.hpp b/src/management/nfd-fib-management-options.hpp
similarity index 63%
rename from src/management/fib-management-options.hpp
rename to src/management/nfd-fib-management-options.hpp
index 58048b5..67e344c 100644
--- a/src/management/fib-management-options.hpp
+++ b/src/management/nfd-fib-management-options.hpp
@@ -7,8 +7,8 @@
  * See COPYING for copyright and distribution information.
  */
 
-#ifndef NDN_FIB_MANAGEMENT_HPP
-#define NDN_FIB_MANAGEMENT_HPP
+#ifndef NDN_MANAGEMENT_NFD_FIB_MANAGEMENT_OPTIONS_HPP
+#define NDN_MANAGEMENT_NFD_FIB_MANAGEMENT_OPTIONS_HPP
 
 #include "../encoding/block.hpp"
 #include "../encoding/encoding-buffer.hpp"
@@ -16,40 +16,73 @@
 #include "../name.hpp"
 
 namespace ndn {
+namespace nfd {
 
 class FibManagementOptions {
 public:
+  struct Error : public Tlv::Error { Error(const std::string &what) : Tlv::Error(what) {} };
+
   FibManagementOptions ()
     : faceId_ (-1)
     , cost_ (-1)
   {
   }
+
+  FibManagementOptions(const Block& block)
+  {
+    wireDecode(block);
+  }
   
   const Name& 
-  getName () const { return name_; }
+  getName () const
+  {
+    return name_;
+  }
   
-  void
-  setName (const Name &name) { name_ = name; wire_.reset (); }
+  FibManagementOptions&
+  setName (const Name &name)
+  {
+    name_ = name;
+    wire_.reset ();
+    return *this;
+  }
   
   int 
-  getFaceId () const { return faceId_; }
+  getFaceId () const
+  {
+    return faceId_;
+  }
 
-  void 
-  setFaceId (int faceId) { faceId_ = faceId; wire_.reset (); }
+  FibManagementOptions&
+  setFaceId (int faceId)
+  {
+    faceId_ = faceId;
+    wire_.reset ();
+    return *this;
+  }
 
   int 
-  getCost () const { return cost_; }
+  getCost () const
+  {
+    return cost_;
+  }
 
-  void 
-  setCost (int cost) { cost_ = cost; wire_.reset (); }
+  FibManagementOptions&
+  setCost (int cost)
+  {
+    cost_ = cost;
+    wire_.reset ();
+    return *this;
+  }
 
-  inline size_t
-  wireEncode (EncodingBuffer& blk);
+  template<bool T>
+  size_t
+  wireEncode(EncodingImpl<T> &block) const;
   
-  inline const Block&
+  const Block&
   wireEncode () const;
   
-  inline void 
+  void 
   wireDecode (const Block &wire);
   
 private:
@@ -62,8 +95,9 @@
   mutable Block wire_;
 };
 
+template<bool T>
 inline size_t
-FibManagementOptions::wireEncode (EncodingBuffer& blk)
+FibManagementOptions::wireEncode(EncodingImpl<T>& blk) const
 {
   size_t total_len = 0;
   if (cost_ != -1)
@@ -89,28 +123,27 @@
   return total_len;
 }
 
+template
+size_t
+FibManagementOptions::wireEncode<true>(EncodingBuffer& block) const;
+
+template
+size_t
+FibManagementOptions::wireEncode<false>(EncodingEstimator& block) const;
+
 inline const Block&
 FibManagementOptions::wireEncode () const
 {
   if (wire_.hasWire ())
     return wire_;
-  
-  wire_ = Block (tlv::nfd_control::FibManagementOptions);
 
-  // Name
-  wire_.push_back (name_.wireEncode ());
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
   
-  // FaceId
-  if (faceId_ != -1)
-    wire_.push_back (nonNegativeIntegerBlock (tlv::nfd_control::FaceId, faceId_));
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
 
-  // Cost
-  if (cost_ != -1)
-    wire_.push_back (nonNegativeIntegerBlock (tlv::nfd_control::Cost, cost_));
-
-  //TODO: Strategy
-  
-  wire_.encode ();
+  wire_ = buffer.block();
   return wire_;
 }
   
@@ -122,6 +155,10 @@
   cost_ = -1;
 
   wire_ = wire;
+
+  if (wire_.type() != tlv::nfd_control::FibManagementOptions)
+    throw Error("Requested decoding of FibManagementOptions, but Block is of different type");
+  
   wire_.parse ();
 
   // Name
@@ -166,6 +203,7 @@
   return os;
 }
 
-}
+} // namespace nfd
+} // namespace ndn
 
-#endif
+#endif // NDN_MANAGEMENT_NFD_FIB_MANAGEMENT_OPTIONS_HPP