face: Refactored code to set interest filter

Change-Id: I1f9637a79c03a9e24608403d963bbfc4d9bcab1c
diff --git a/src/management/ndnd-control.cpp b/src/management/ndnd-control.cpp
new file mode 100644
index 0000000..6f48231
--- /dev/null
+++ b/src/management/ndnd-control.cpp
@@ -0,0 +1,264 @@
+/* -*- 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 "../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 {
+
+Control::Control(Node& face)
+  : m_face(face)
+  , m_faceId(-1)
+{
+}
+
+void
+Control::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));
+        }
+      m_filterRequests.push_back(FilterRequest(prefixToRegister, onSuccess, onFail));
+    }
+  else
+    startPrefixAction(ForwardingEntry("selfreg", prefixToRegister),
+                      bind(&Control::recordSelfRegisteredFaceId, this, _1, onSuccess),
+                      onFail);
+}
+
+
+void
+Control::selfDeregisterPrefix(const Name& prefixToRegister,
+                              const SuccessCallback& onSuccess,
+                              const FailCallback&    onFail)
+{
+  if (!m_ndndId.hasValue() || m_faceId == -1)
+    {
+      if (static_cast<bool>(onFail))
+        onFail();
+      return;
+    }
+
+  startPrefixAction(ForwardingEntry("unreg", prefixToRegister, m_faceId),
+                    bind(onSuccess), onFail);
+}
+
+
+void 
+Control::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(&Control::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();
+        }
+    }
+  m_filterRequests.clear();
+}
+
+void
+Control::recordSelfRegisteredFaceId(const ForwardingEntry& entry,
+                                    const SuccessCallback& onSuccess)
+{
+  m_faceId = entry.getFaceId();
+  if (static_cast<bool>(onSuccess))
+    onSuccess();
+}
+
+void
+Control::startFaceAction(const FaceInstance& entry,
+                         const FaceOperationSucceedCallback& onSuccess,
+                         const FailCallback& onFailure)
+{
+  // 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(&Control::processFaceActionResponse, this, _2, onSuccess, onFailure),
+                         bind(onFailure));
+}
+
+void
+Control::startPrefixAction(const ForwardingEntry& entry,
+                           const PrefixOperationSucceedCallback& onSuccess,
+                           const FailCallback& onFailure)
+{
+  // 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(&Control::processPrefixActionResponse, this, _2, onSuccess, onFailure),
+                         bind(onFailure));
+}
+
+void
+Control::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();
+      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();
+        return;
+      }
+    default:
+      {
+        if (static_cast<bool>(onFail))
+          onFail();
+        return;
+      }
+    }
+}
+
+void
+Control::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();
+      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();
+        return;
+      }
+    default:
+      {
+        if (static_cast<bool>(onFail))
+          onFail();
+        return;
+      }
+    }
+}
+
+} // namespace ndnd
+} // namespace ndn
diff --git a/src/management/ndnd-control.hpp b/src/management/ndnd-control.hpp
new file mode 100644
index 0000000..fd22f15
--- /dev/null
+++ b/src/management/ndnd-control.hpp
@@ -0,0 +1,109 @@
+/* -*- 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_NDND_CONTROL_HPP
+#define NDN_MANAGEMENT_NDND_CONTROL_HPP
+
+#include "../common.hpp"
+
+namespace ndn {
+
+class Node;
+
+namespace ndnd {
+
+class FaceInstance;
+class ForwardingEntry;
+
+/*
+ * @brief Class implementing Face and Prefix management operations for ndnd-tlv
+ *
+ * ndnd::Control should be used when connecting to ndnd-tlv daemon
+ */
+class Control
+{
+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);
+
+  void
+  selfRegisterPrefix(const Name& prefixToRegister,
+                     const SuccessCallback& onSuccess,
+                     const FailCallback&    onFail);
+
+  void
+  selfDeregisterPrefix(const Name& prefixToRegister,
+                       const SuccessCallback& onSuccess,
+                       const FailCallback&    onFail);
+
+protected:
+  void
+  startFaceAction(const FaceInstance& entry,
+                  const FaceOperationSucceedCallback& onSuccess,
+                  const FailCallback& onFailure);
+
+  void
+  startPrefixAction(const ForwardingEntry& entry,
+                    const PrefixOperationSucceedCallback& onSuccess,
+                    const FailCallback& onFailure);
+
+private:
+  void 
+  onNdnidFetched(const shared_ptr<const Interest>& interest,
+                 const shared_ptr<Data>& data);
+
+
+  void
+  recordSelfRegisteredFaceId(const ForwardingEntry& entry,
+                             const SuccessCallback& onSuccess);
+
+  void
+  processFaceActionResponse(const shared_ptr<Data>& data,
+                            const FaceOperationSucceedCallback& onSuccess,
+                            const FailCallback&    onFail);
+
+  void
+  processPrefixActionResponse(const shared_ptr<Data>& data,
+                              const PrefixOperationSucceedCallback& onSuccess,
+                              const FailCallback&    onFail);
+
+private:
+  Node& m_face;
+  Block m_ndndId;
+  int64_t m_faceId; // internal face ID (needed for prefix de-registration)
+
+  struct FilterRequest
+  {
+    FilterRequest(const Name& prefixToRegister,
+                  const SuccessCallback& onSuccess,
+                  const FailCallback&    onFailure)
+      : m_prefixToRegister(prefixToRegister)
+      , m_onSuccess(onSuccess)
+      , m_onFailure(onFailure)
+    {
+    }
+    
+    Name             m_prefixToRegister;
+    SuccessCallback  m_onSuccess;
+    FailCallback     m_onFailure;
+  };
+
+  typedef std::list<FilterRequest> FilterRequestList;
+  FilterRequestList m_filterRequests;
+};
+
+} // namespace ndnd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NDND_CONTROL_HPP
diff --git a/src/management/ndnd-face-instance.hpp b/src/management/ndnd-face-instance.hpp
new file mode 100644
index 0000000..03a8589
--- /dev/null
+++ b/src/management/ndnd-face-instance.hpp
@@ -0,0 +1,346 @@
+/* -*- 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_NDND_FACE_INSTANCE_HPP
+#define NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
+
+#include "../encoding/tlv-face-management.hpp"
+#include "../encoding/block.hpp"
+#include "../name.hpp"
+
+namespace ndn {
+namespace ndnd {
+
+/**
+ * An FaceInstance holds an action and  Name prefix and other fields for an forwarding entry.
+ */
+class FaceInstance {
+public:    
+  FaceInstance(const std::string &action,
+               int64_t     faceId,
+               uint32_t    ipProto,
+               const std::string &host,
+               const std::string &port,
+               const std::string &multicastInterface,
+               uint32_t    multicastTtl,
+               Milliseconds freshnessPeriod) 
+    : action_(action)
+    , faceId_(faceId)
+    , ipProto_(ipProto)
+    , host_(host)
+    , port_(port)
+    , multicastInterface_(multicastInterface)
+    , multicastTtl_(multicastTtl)
+    , freshnessPeriod_(freshnessPeriod)
+  {
+  }
+
+  FaceInstance()
+    : faceId_(-1)
+    , ipProto_(-1)
+    , multicastTtl_(-1)
+    , freshnessPeriod_(-1)
+  {
+  }
+
+  // Action
+  const std::string& 
+  getAction() const { return action_; }
+
+  void 
+  setAction(const std::string& action) { action_ = action; wire_.reset(); }
+
+  // FaceID
+  int64_t
+  getFaceId() const { return faceId_; }
+
+  void 
+  setFaceId(int64_t faceId) { faceId_ = faceId; wire_.reset(); }
+
+  // IPProto
+  int32_t 
+  getIpProto() const { return ipProto_; }
+
+  void 
+  setIpProto(int32_t ipProto) { ipProto_ = ipProto; wire_.reset(); }
+
+  // Host
+  const std::string& 
+  getHost() const { return host_; }
+
+  void 
+  setHost(const std::string& host) { host_ = host; wire_.reset(); }
+
+  // Port
+  const std::string&
+  getPort() const { return port_; }
+
+  void 
+  setPort(const std::string &port) { port_ = port; wire_.reset(); }
+
+  // MulticastInterface
+  const std::string& 
+  getMulticastInterface() const { return multicastInterface_; }
+
+  void 
+  setMulticastInterface(const std::string& multicastInterface) { multicastInterface_ = multicastInterface; wire_.reset(); }
+
+  // MulticastTTL
+  int32_t
+  getMulticastTtl() const { return multicastTtl_; }
+
+  void 
+  setMulticastTtl(int32_t multicastTtl) { multicastTtl_ = multicastTtl; wire_.reset(); }
+
+  // Freshness
+  int 
+  getFreshnessPeriod() const { return freshnessPeriod_; }
+
+  void 
+  setFreshnessPeriod(int freshnessPeriod) { freshnessPeriod_ = freshnessPeriod; wire_.reset(); }
+
+  // Wire
+  inline const Block&
+  wireEncode() const;
+  
+  inline void 
+  wireDecode(const Block &wire);
+  
+private:
+  std::string action_;
+  int64_t     faceId_;
+  int32_t     ipProto_;
+  std::string host_;
+  std::string port_;
+  std::string multicastInterface_;
+  int32_t     multicastTtl_;
+  Milliseconds freshnessPeriod_;
+  
+  mutable Block wire_;
+};
+
+inline const Block&
+FaceInstance::wireEncode() const
+{
+  if (wire_.hasWire())
+    return wire_;
+
+  // FaceInstance ::= FACE-INSTANCE-TYPE TLV-LENGTH
+  //                  Action?
+  //                  FaceID?
+  //                  IPProto?
+  //                  Host?
+  //                  Port?
+  //                  MulticastInterface?
+  //                  MulticastTTL?
+  //                  FreshnessPeriod?
+  
+  wire_ = Block(Tlv::FaceManagement::FaceInstance);
+
+  // Action
+  if (!action_.empty())
+    {
+      wire_.push_back
+        (dataBlock(Tlv::FaceManagement::Action, action_.c_str(), action_.size()));
+    }
+
+  // FaceID
+  if (faceId_ >= 0)
+    {
+      wire_.push_back
+        (nonNegativeIntegerBlock(Tlv::FaceManagement::FaceID, faceId_));
+    }
+
+  // IPProto
+  if (ipProto_ >= 0)
+    {
+      wire_.push_back
+        (nonNegativeIntegerBlock(Tlv::FaceManagement::IPProto, ipProto_));
+    }
+  
+  // Host
+  if (!host_.empty())
+    {
+      wire_.push_back
+        (dataBlock(Tlv::FaceManagement::Host, host_.c_str(), host_.size()));
+    }
+
+  // Port
+  if (!port_.empty())
+    {
+      wire_.push_back
+        (dataBlock(Tlv::FaceManagement::Port, port_.c_str(), port_.size()));
+    }
+
+  // MulticastInterface
+  if (!multicastInterface_.empty())
+    {
+      wire_.push_back
+        (dataBlock(Tlv::FaceManagement::MulticastInterface, multicastInterface_.c_str(), multicastInterface_.size()));
+    }
+
+  // MulticastTTL
+  if (multicastTtl_ >= 0)
+    {
+      wire_.push_back
+        (nonNegativeIntegerBlock(Tlv::FaceManagement::MulticastTTL, multicastTtl_));
+    }
+
+  // FreshnessPeriod
+  if (freshnessPeriod_ >= 0)
+    {
+      wire_.push_back
+        (nonNegativeIntegerBlock(Tlv::FreshnessPeriod, freshnessPeriod_));
+    }
+  
+  wire_.encode();
+  return wire_;    
+}
+  
+inline void 
+FaceInstance::wireDecode(const Block &wire)
+{
+  action_.clear();
+  faceId_ = -1;
+  ipProto_ = -1;
+  host_.clear();
+  port_.clear();
+  multicastInterface_.clear();
+  multicastTtl_ = -1;
+  freshnessPeriod_ = -1;
+
+  wire_ = wire;
+  wire_.parse();
+
+  // FaceInstance ::= FACE-INSTANCE-TYPE TLV-LENGTH
+  //                  Action?
+  //                  FaceID?
+  //                  IPProto?
+  //                  Host?
+  //                  Port?
+  //                  MulticastInterface?
+  //                  MulticastTTL?
+  //                  FreshnessPeriod?
+
+  // Action
+  Block::element_iterator val = wire_.find(Tlv::FaceManagement::Action);
+  if (val != wire_.getAll().end())
+    {
+      action_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
+    }
+
+  // FaceID
+  val = wire_.find(Tlv::FaceManagement::FaceID);
+  if (val != wire_.getAll().end())
+    {
+      faceId_ = readNonNegativeInteger(*val);
+    }
+
+  // IPProto
+  val = wire_.find(Tlv::FaceManagement::IPProto);
+  if (val != wire_.getAll().end())
+    {
+      ipProto_ = readNonNegativeInteger(*val);
+    }
+
+  // Host
+  val = wire_.find(Tlv::FaceManagement::Host);
+  if (val != wire_.getAll().end())
+    {
+      host_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
+    }
+
+  // Port
+  val = wire_.find(Tlv::FaceManagement::Port);
+  if (val != wire_.getAll().end())
+    {
+      port_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
+    }
+
+  // MulticastInterface
+  val = wire_.find(Tlv::FaceManagement::MulticastInterface);
+  if (val != wire_.getAll().end())
+    {
+      multicastInterface_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
+    }
+
+  // MulticastTTL
+  val = wire_.find(Tlv::FaceManagement::MulticastTTL);
+  if (val != wire_.getAll().end())
+    {
+      multicastTtl_ = readNonNegativeInteger(*val);
+    }
+
+  // FreshnessPeriod
+  val = wire_.find(Tlv::FreshnessPeriod);
+  if (val != wire_.getAll().end())
+    {
+      freshnessPeriod_ = readNonNegativeInteger(*val);
+    }
+}
+
+inline std::ostream&
+operator << (std::ostream &os, const FaceInstance &entry)
+{
+  os << "FaceInstance(";
+  
+  // Action
+  if (!entry.getAction().empty())
+    {
+      os << "Action:" << entry.getAction() << ", ";
+    }
+
+  // FaceID
+  if (entry.getFaceId() >= 0)
+    {
+      os << "FaceID:" << entry.getFaceId() << ", ";
+    }
+
+  // IPProto
+  if (entry.getIpProto() >= 0)
+    {
+      os << "IPProto:" << entry.getIpProto() << ", ";
+    }
+
+  // Host
+  if (!entry.getHost().empty())
+    {
+      os << "Host:" << entry.getHost() << ", ";
+    }
+
+  // Port
+  if (!entry.getPort().empty())
+    {
+      os << "Port:" << entry.getPort() << ", ";
+    }
+
+  // MulticastInterface
+  if (!entry.getMulticastInterface().empty())
+    {
+      os << "MulticastInterface:" << entry.getMulticastInterface() << ", ";
+    }
+
+  // MulticastTTL
+  if (entry.getMulticastTtl() >= 0)
+    {
+      os << "MulticastTTL:" << entry.getMulticastTtl() << ", ";
+    }
+
+  // FreshnessPeriod
+  if (entry.getFreshnessPeriod() >= 0)
+    {
+      os << "FreshnessPeriod:" << entry.getFreshnessPeriod() << ", ";
+    }
+
+  os << ")";
+  return os;
+}
+
+} // namespace ndnd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
+
diff --git a/src/management/ndnd-forwarding-entry.hpp b/src/management/ndnd-forwarding-entry.hpp
new file mode 100644
index 0000000..0a02c7e
--- /dev/null
+++ b/src/management/ndnd-forwarding-entry.hpp
@@ -0,0 +1,228 @@
+/* -*- 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_NDND_FORWARDING_ENTRY_HPP
+#define NDN_MANAGEMENT_NDND_FORWARDING_ENTRY_HPP
+
+#include "../encoding/tlv-face-management.hpp"
+#include "../name.hpp"
+#include "../encoding/block.hpp"
+
+#include "ndnd-forwarding-flags.hpp"
+
+namespace ndn {
+namespace ndnd {
+
+/**
+ * An ForwardingEntry holds an action and  Name prefix and other fields for an forwarding entry.
+ */
+class ForwardingEntry {
+public:    
+  ForwardingEntry(const std::string& action,
+                  const Name& prefix,
+                  int faceId = -1,
+                  const ForwardingFlags& forwardingFlags = ForwardingFlags(),
+                  int freshnessPeriod = -1) 
+    : action_(action)
+    , prefix_(prefix)
+    , faceId_(faceId)
+    , forwardingFlags_(forwardingFlags)
+    , freshnessPeriod_(freshnessPeriod)
+  {
+  }
+
+  ForwardingEntry()
+  : faceId_(-1)
+  , freshnessPeriod_(-1)
+  {
+  }
+  
+  const std::string& 
+  getAction() const { return action_; }
+
+  void 
+  setAction(const std::string& action) { action_ = action; wire_.reset(); }
+    
+  const Name& 
+  getPrefix() const { return prefix_; }
+  
+  void
+  setPrefix(const Name &prefix) { prefix_ = prefix; wire_.reset(); }
+  
+  int 
+  getFaceId() const { return faceId_; }
+
+  void 
+  setFaceId(int faceId) { faceId_ = faceId; wire_.reset(); }
+      
+  const ForwardingFlags& 
+  getForwardingFlags() const { return forwardingFlags_; }
+
+  void 
+  setForwardingFlags(const ForwardingFlags& forwardingFlags) { forwardingFlags_ = forwardingFlags; wire_.reset(); }
+      
+  int 
+  getFreshnessPeriod() const { return freshnessPeriod_; }
+
+  void 
+  setFreshnessPeriod(int freshnessPeriod) { freshnessPeriod_ = freshnessPeriod; wire_.reset(); }
+
+  inline const Block&
+  wireEncode() const;
+  
+  inline void 
+  wireDecode(const Block &wire);
+  
+private:
+  std::string action_;   /**< empty for none. */
+  Name prefix_;
+  int faceId_;           /**< -1 for none. */
+  ForwardingFlags forwardingFlags_;
+  int freshnessPeriod_; /**< -1 for none. */
+
+  mutable Block wire_;
+};
+
+inline const Block&
+ForwardingEntry::wireEncode() const
+{
+  if (wire_.hasWire())
+    return wire_;
+
+  // ForwardingEntry ::= FORWARDING-ENTRY TLV-LENGTH
+  //                       Action?
+  //                       Name?
+  //                       FaceID?
+  //                       ForwardingFlags?
+  //                       FreshnessPeriod?
+  
+  wire_ = Block(Tlv::FaceManagement::ForwardingEntry);
+
+  // Action
+  if (!action_.empty())
+    {
+      wire_.push_back
+        (dataBlock(Tlv::FaceManagement::Action, action_.c_str(), action_.size()));
+    }
+
+  // Name
+  wire_.push_back
+    (prefix_.wireEncode());
+
+  // FaceID
+  if (faceId_ >= 0)
+    {
+      wire_.push_back
+        (nonNegativeIntegerBlock(Tlv::FaceManagement::FaceID, faceId_));
+    }
+
+  // ForwardingFlags
+  wire_.push_back
+    (forwardingFlags_.wireEncode());
+
+  // FreshnessPeriod
+  if (freshnessPeriod_ >= 0)
+    {
+      wire_.push_back
+        (nonNegativeIntegerBlock(Tlv::FreshnessPeriod, freshnessPeriod_));
+    }
+  
+  wire_.encode();
+  return wire_;    
+}
+  
+inline void 
+ForwardingEntry::wireDecode(const Block &wire)
+{
+  action_.clear();
+  prefix_.clear();
+  faceId_ = -1;
+  forwardingFlags_ = ForwardingFlags();
+  freshnessPeriod_ = -1;
+
+  wire_ = wire;
+  wire_.parse();
+
+  // ForwardingEntry ::= FORWARDING-ENTRY TLV-LENGTH
+  //                       Action?
+  //                       Name?
+  //                       FaceID?
+  //                       ForwardingFlags?
+  //                       FreshnessPeriod?
+
+  // Action
+  Block::element_iterator val = wire_.find(Tlv::FaceManagement::Action);
+  if (val != wire_.getAll().end())
+    {
+      action_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
+    }
+
+  // Name
+  val = wire_.find(Tlv::Name);
+  if (val != wire_.getAll().end())
+    {
+      prefix_.wireDecode(*val);
+    }
+
+  // FaceID
+  val = wire_.find(Tlv::FaceManagement::FaceID);
+  if (val != wire_.getAll().end())
+    {
+      faceId_ = readNonNegativeInteger(*val);
+    }
+
+  // ForwardingFlags
+  val = wire_.find(Tlv::FaceManagement::ForwardingFlags);
+  if (val != wire_.getAll().end())
+    {
+      forwardingFlags_.wireDecode(*val);
+    }
+
+  // FreshnessPeriod
+  val = wire_.find(Tlv::FreshnessPeriod);
+  if (val != wire_.getAll().end())
+    {
+      freshnessPeriod_ = readNonNegativeInteger(*val);
+    }
+}
+
+inline std::ostream&
+operator << (std::ostream &os, const ForwardingEntry &entry)
+{
+  os << "ForwardingEntry(";
+  
+  // Action
+  if (!entry.getAction().empty())
+    {
+      os << "Action:" << entry.getAction() << ", ";
+    }
+
+  // Name
+  os << "Prefix:" << entry.getPrefix() << ", ";
+
+  // FaceID
+  if (entry.getFaceId() >= 0)
+    {
+      os << "FaceID:" << entry.getFaceId() << ", ";
+    }
+
+  // ForwardingFlags
+  os << "ForwardingFlags:" << entry.getForwardingFlags() << ", ";
+
+  // FreshnessPeriod
+  if (entry.getFreshnessPeriod() >= 0)
+    {
+      os << "FreshnessPeriod:" << entry.getFreshnessPeriod() << ", ";
+    }
+
+  os << ")";
+  return os;
+}
+
+} // namespace ndnd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NDND_FORWARDING_ENTRY_HPP
diff --git a/src/management/ndnd-forwarding-flags.hpp b/src/management/ndnd-forwarding-flags.hpp
new file mode 100644
index 0000000..8b4ce78
--- /dev/null
+++ b/src/management/ndnd-forwarding-flags.hpp
@@ -0,0 +1,226 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Jeff Thompson <jefft0@remap.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_FORWARDING_FLAGS_HPP
+#define NDN_FORWARDING_FLAGS_HPP
+
+#include "../encoding/block.hpp"
+#include "../encoding/tlv-face-management.hpp"
+
+namespace ndn {
+namespace ndnd {
+
+/**
+ * A ForwardingFlags object holds the flags which specify how the forwarding daemon should forward an interest for
+ * a registered prefix.  We use a separate ForwardingFlags object to retain future compatibility if the daemon forwarding
+ * bits are changed, amended or deprecated.
+ */
+class ForwardingFlags {
+public:
+  /**
+   * Create a new ForwardingFlags with "active" and "childInherit" set and all other flags cleared.
+   */
+  ForwardingFlags() 
+    : active_(true)
+    , childInherit_(true)
+    , advertise_(false)
+    , last_(false)
+    , capture_(false)
+    , local_(false)
+    , tap_(false)
+    , captureOk_(false)
+  {
+  }
+
+  /**
+   * Get the value of the "active" flag.
+   * @return true if the flag is set, false if it is cleared.
+   */
+  bool getActive() const { return active_; }
+  
+  /**
+   * Get the value of the "childInherit" flag.
+   * @return true if the flag is set, false if it is cleared.
+   */
+  bool getChildInherit() const { return childInherit_; }
+  
+  /**
+   * Get the value of the "advertise" flag.
+   * @return true if the flag is set, false if it is cleared.
+   */
+  bool getAdvertise() const { return advertise_; }
+  
+  /**
+   * Get the value of the "last" flag.
+   * @return true if the flag is set, false if it is cleared.
+   */
+  bool getLast() const { return last_; }
+  
+  /**
+   * Get the value of the "capture" flag.
+   * @return true if the flag is set, false if it is cleared.
+   */
+  bool getCapture() const { return capture_; }
+  
+  /**
+   * Get the value of the "local" flag.
+   * @return true if the flag is set, false if it is cleared.
+   */
+  bool getLocal() const { return local_; }
+  
+  /**
+   * Get the value of the "tap" flag.
+   * @return true if the flag is set, false if it is cleared.
+   */
+  bool getTap() const { return tap_; }
+  
+  /**
+   * Get the value of the "captureOk" flag.
+   * @return true if the flag is set, false if it is cleared.
+   */
+  bool getCaptureOk() const { return captureOk_; }
+
+  /**
+   * Set the value of the "active" flag
+   * @param active true to set the flag, false to clear it.
+   */  
+  void setActive(bool active) { this->active_ = active; wire_.reset(); }
+  
+  /**
+   * Set the value of the "childInherit" flag
+   * @param childInherit true to set the flag, false to clear it.
+   */  
+  void setChildInherit(bool childInherit) { this->childInherit_ = childInherit; wire_.reset(); }
+  
+  /**
+   * Set the value of the "advertise" flag
+   * @param advertise true to set the flag, false to clear it.
+   */  
+  void setAdvertise(bool advertise) { this->advertise_ = advertise; wire_.reset(); }
+  
+  /**
+   * Set the value of the "last" flag
+   * @param last true to set the flag, false to clear it.
+   */  
+  void setLast(bool last) { this->last_ = last; wire_.reset(); }
+  
+  /**
+   * Set the value of the "capture" flag
+   * @param capture true to set the flag, false to clear it.
+   */  
+  void setCapture(bool capture) { this->capture_ = capture; wire_.reset(); }
+  
+  /**
+   * Set the value of the "local" flag
+   * @param local true to set the flag, false to clear it.
+   */  
+  void setLocal(bool local) { this->local_ = local; wire_.reset(); }
+  
+  /**
+   * Set the value of the "tap" flag
+   * @param tap true to set the flag, false to clear it.
+   */  
+  void setTap(bool tap) { this->tap_ = tap; wire_.reset(); }
+  
+  /**
+   * Set the value of the "captureOk" flag
+   * @param captureOk true to set the flag, false to clear it.
+   */  
+  void setCaptureOk(bool captureOk) { this->captureOk_ = captureOk; wire_.reset(); }
+
+  inline const Block&
+  wireEncode() const;
+
+  inline void
+  wireDecode(const Block &block);
+  
+private:
+  bool active_;
+  bool childInherit_;
+  bool advertise_;
+  bool last_;
+  bool capture_;
+  bool local_;
+  bool tap_;
+  bool captureOk_;
+
+  mutable Block wire_;
+};
+
+inline const Block&
+ForwardingFlags::wireEncode() const
+{
+  if (wire_.hasWire())
+    return wire_;
+
+  uint32_t result = 0;
+  if (active_)
+    result |= Tlv::FaceManagement::FORW_ACTIVE;
+  if (childInherit_)
+    result |= Tlv::FaceManagement::FORW_CHILD_INHERIT;
+  if (advertise_)
+    result |= Tlv::FaceManagement::FORW_ADVERTISE;
+  if (last_)
+    result |= Tlv::FaceManagement::FORW_LAST;
+  if (capture_)
+    result |= Tlv::FaceManagement::FORW_CAPTURE;
+  if (local_)
+    result |= Tlv::FaceManagement::FORW_LOCAL;
+  if (tap_)
+    result |= Tlv::FaceManagement::FORW_TAP;
+  if (captureOk_)
+    result |= Tlv::FaceManagement::FORW_CAPTURE_OK;
+  
+  wire_ = nonNegativeIntegerBlock(Tlv::FaceManagement::ForwardingFlags, result);
+
+  return wire_;
+}
+
+inline void
+ForwardingFlags::wireDecode(const Block &wire)
+{
+  wire_ = wire;
+
+  uint32_t flags = readNonNegativeInteger(wire_);
+  
+  active_       = (flags & Tlv::FaceManagement::FORW_ACTIVE)        ? true : false;
+  childInherit_ = (flags & Tlv::FaceManagement::FORW_CHILD_INHERIT) ? true : false;
+  advertise_    = (flags & Tlv::FaceManagement::FORW_ADVERTISE)     ? true : false;
+  last_         = (flags & Tlv::FaceManagement::FORW_LAST)          ? true : false;
+  capture_      = (flags & Tlv::FaceManagement::FORW_CAPTURE)       ? true : false;
+  local_        = (flags & Tlv::FaceManagement::FORW_LOCAL)         ? true : false;
+  tap_          = (flags & Tlv::FaceManagement::FORW_TAP)           ? true : false;
+  captureOk_    = (flags & Tlv::FaceManagement::FORW_CAPTURE_OK)    ? true : false;
+}
+
+inline std::ostream&
+operator << (std::ostream &os, const ForwardingFlags &flags)
+{
+  if (flags.getActive())
+    os << "ACTIVE ";
+  if (flags.getChildInherit())
+    os << "CHILE_INHERIT ";
+  if (flags.getAdvertise())
+    os << "ADVERTISE ";
+  if (flags.getLast())
+    os << "LAST ";
+  if (flags.getCapture())
+    os << "CAPTURE ";
+  if (flags.getLocal())
+    os << "LOCAL ";
+  if (flags.getTap())
+    os << "TAP ";
+  if (flags.getCaptureOk())
+    os << "CAPTURE_OK ";
+
+  return os;
+}
+
+} // namespace ndnd
+} // namespace ndn
+
+#endif
diff --git a/src/management/ndnd-status-response.hpp b/src/management/ndnd-status-response.hpp
new file mode 100644
index 0000000..1543bed
--- /dev/null
+++ b/src/management/ndnd-status-response.hpp
@@ -0,0 +1,126 @@
+/* -*- 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_NDND_STATUS_RESPONSE_HPP
+#define NDN_MANAGEMENT_NDND_STATUS_RESPONSE_HPP
+
+#include "../encoding/block.hpp"
+#include "../encoding/tlv-face-management.hpp"
+
+namespace ndn {
+namespace ndnd {
+
+class StatusResponse {
+public:
+  StatusResponse()
+    : code_(0)
+  {
+  }
+
+  StatusResponse(uint32_t code, const std::string &info)
+    : code_(code)
+    , info_(info)
+  {
+  }
+  
+  inline uint32_t
+  getCode() const;
+
+  inline void
+  setCode(uint32_t code);
+
+  inline const std::string &
+  getInfo() const;
+
+  inline void
+  setInfo(const std::string &info);
+
+  inline const Block&
+  wireEncode() const;
+
+  inline void
+  wireDecode(const Block &block);
+  
+private:
+  uint32_t code_;
+  std::string info_;
+
+  mutable Block wire_;
+};
+
+inline uint32_t
+StatusResponse::getCode() const
+{
+  return code_;
+}
+
+inline void
+StatusResponse::setCode(uint32_t code)
+{
+  code_ = code;
+  wire_.reset();
+}
+
+inline const std::string &
+StatusResponse::getInfo() const
+{
+  return info_;
+}
+
+inline void
+StatusResponse::setInfo(const std::string &info)
+{
+  info_ = info;
+  wire_.reset();
+}
+
+
+inline const Block&
+StatusResponse::wireEncode() const
+{
+  if (wire_.hasWire())
+    return wire_;
+
+  wire_ = Block(Tlv::FaceManagement::StatusResponse);
+  wire_.push_back
+    (nonNegativeIntegerBlock(Tlv::FaceManagement::StatusCode, code_));
+
+  if (!info_.empty())
+    {
+      wire_.push_back
+        (dataBlock(Tlv::FaceManagement::StatusText, info_.c_str(), info_.size()));
+    }
+  
+  wire_.encode();  
+  return wire_;
+}
+
+inline void
+StatusResponse::wireDecode(const Block &wire)
+{
+  wire_ = wire;
+  wire_.parse();
+
+  code_ = readNonNegativeInteger(wire_.get(Tlv::FaceManagement::StatusCode));
+
+  Block::element_iterator val = wire_.find(Tlv::FaceManagement::StatusText);
+  if (val != wire_.getAll().end())
+    {
+      info_.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
+    }
+}
+
+inline std::ostream&
+operator << (std::ostream &os, const StatusResponse &status)
+{
+  os << status.getCode() << " " << status.getInfo();
+  return os;
+}
+
+} // namespace ndnd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NDND_STATUS_RESPONSE_HPP
diff --git a/src/management/nfd-control.hpp b/src/management/nfd-control.hpp
new file mode 100644
index 0000000..642afd8
--- /dev/null
+++ b/src/management/nfd-control.hpp
@@ -0,0 +1,14 @@
+/* -*- 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