face: Refactored code to set interest filter

Change-Id: I1f9637a79c03a9e24608403d963bbfc4d9bcab1c
diff --git a/src/detail/pending-interest.hpp b/src/detail/pending-interest.hpp
new file mode 100644
index 0000000..85acb23
--- /dev/null
+++ b/src/detail/pending-interest.hpp
@@ -0,0 +1,112 @@
+/* -*- 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_DETAIL_PENDING_INTEREST_HPP
+#define NDN_DETAIL_PENDING_INTEREST_HPP
+
+#include "../common.hpp"
+#include "../interest.hpp"
+#include "../data.hpp"
+#include "../util/time.hpp"
+
+namespace ndn {
+
+class PendingInterest {
+public:
+  typedef function<void(const shared_ptr<const Interest>&, const shared_ptr<Data>&)> OnData;
+  typedef function<void(const shared_ptr<const Interest>&)> OnTimeout;
+
+  /**
+   * Create a new PitEntry and set the timeoutTime_ based on the current time and the interest lifetime.
+   * @param interest A shared_ptr for the interest.
+   * @param onData A function object to call when a matching data packet is received.
+   * @param onTimeout A function object to call if the interest times out.  If onTimeout is an empty OnTimeout(), this does not use it.
+   */
+  PendingInterest(const shared_ptr<const Interest>& interest, const OnData& onData, 
+                  const OnTimeout& onTimeout)
+    : interest_(interest),
+      onData_(onData), onTimeout_(onTimeout)
+  {
+    // Set up timeoutTime_.
+    if (interest_->getInterestLifetime() >= 0)
+      timeoutTimeMilliseconds_ = getNowMilliseconds() + interest_->getInterestLifetime();
+    else
+      // No timeout.
+      /**
+       * @todo Set more meaningful default timeout.  This timeout MUST exist.
+       */
+      timeoutTimeMilliseconds_ = getNowMilliseconds() + 4000;
+  }
+    
+  const shared_ptr<const Interest>& 
+  getInterest()
+  {
+    return interest_;
+  }
+    
+  const OnData& 
+  getOnData()
+  {
+    return onData_;
+  }
+    
+  /**
+   * Check if this interest is timed out.
+   * @param nowMilliseconds The current time in milliseconds from getNowMilliseconds.
+   * @return true if this interest timed out, otherwise false.
+   */
+  bool 
+  isTimedOut(MillisecondsSince1970 nowMilliseconds)
+  {
+    return timeoutTimeMilliseconds_ >= 0.0 && nowMilliseconds >= timeoutTimeMilliseconds_;
+  }
+
+  /**
+   * Call onTimeout_ (if defined).  This ignores exceptions from the onTimeout_.
+   */
+  void 
+  callTimeout()
+  {
+    if (onTimeout_) {
+      onTimeout_(interest_);
+    }
+  }
+    
+private:
+  shared_ptr<const Interest> interest_;
+  const OnData onData_;
+  const OnTimeout onTimeout_;
+
+  /** The time when the interest times out in milliseconds according to getNowMilliseconds, or -1 for no timeout. */
+  MillisecondsSince1970 timeoutTimeMilliseconds_;
+};
+
+
+struct PendingInterestId;
+
+/**
+ * @brief Functor to match pending interests against PendingInterestId
+ */
+struct MatchPendingInterestId
+{
+  MatchPendingInterestId(const PendingInterestId *pendingInterestId)
+    : id_(pendingInterestId)
+  {
+  }
+
+  bool
+  operator()(const shared_ptr<const PendingInterest> &pendingInterest) const
+  {
+    return (reinterpret_cast<const PendingInterestId *>(pendingInterest.get()) == id_);
+  }
+private:
+  const PendingInterestId *id_;
+};
+
+
+} // namespace ndn
+
+#endif // NDN_DETAIL_PENDING_INTEREST_HPP
diff --git a/src/detail/registered-prefix.hpp b/src/detail/registered-prefix.hpp
new file mode 100644
index 0000000..5cb5523
--- /dev/null
+++ b/src/detail/registered-prefix.hpp
@@ -0,0 +1,72 @@
+/* -*- 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_DETAIL_REGISTERED_PREFIX_HPP
+#define NDN_DETAIL_REGISTERED_PREFIX_HPP
+
+#include "../common.hpp"
+#include "../interest.hpp"
+
+namespace ndn {
+
+class RegisteredPrefix {
+public:
+  typedef function<void
+  (const shared_ptr<const Name>&, const shared_ptr<const Interest>&)> OnInterest;
+
+  /**
+   * Create a new PrefixEntry.
+   * @param prefix A shared_ptr for the prefix.
+   * @param onInterest A function object to call when a matching data packet is received.
+   */
+  RegisteredPrefix(const Name& prefix, const OnInterest& onInterest)
+    : prefix_(new Name(prefix))
+    , onInterest_(onInterest)
+  {
+  }
+    
+  const Name& 
+  getPrefix() const
+  {
+    return *prefix_;
+  }
+    
+  const OnInterest& 
+  getOnInterest() const
+  {
+    return onInterest_;
+  }
+    
+private:
+  shared_ptr<Name> prefix_;
+  const OnInterest onInterest_;
+};
+
+
+struct RegisteredPrefixId;
+
+/**
+ * @brief Functor to match pending interests against PendingInterestId
+ */
+struct MatchRegisteredPrefixId
+{
+  MatchRegisteredPrefixId(const RegisteredPrefixId *registeredPrefixId)
+    : id_(registeredPrefixId)
+  {
+  }
+
+  bool
+  operator()(const shared_ptr<RegisteredPrefix> &registeredPrefix) const
+  {
+    return (reinterpret_cast<const RegisteredPrefixId *>(registeredPrefix.get()) == id_);
+  }
+private:
+  const RegisteredPrefixId *id_;
+};
+
+} // namespace ndn
+
+#endif // NDN_DETAIL_REGISTERED_PREFIX_HPP
diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp
index fbd5838..98c131a 100644
--- a/src/encoding/block.cpp
+++ b/src/encoding/block.cpp
@@ -175,8 +175,8 @@
   , m_type(type)
   , m_begin(m_buffer->end())
   , m_end(m_buffer->end())
-  , m_value_begin(m_buffer->begin())
-  , m_value_end(m_buffer->end())
+  , m_value_begin(value.begin())
+  , m_value_end(value.end())
 {
   m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
 }
diff --git a/src/face.hpp b/src/face.hpp
index a757061..13fdd6f 100644
--- a/src/face.hpp
+++ b/src/face.hpp
@@ -140,9 +140,9 @@
    */
   const RegisteredPrefixId*
   setInterestFilter
-    (const Name& prefix, const OnInterest& onInterest, const OnRegisterFailed& onRegisterFailed, const ForwardingFlags& flags = ForwardingFlags())
+    (const Name& prefix, const OnInterest& onInterest, const OnSetInterestFilterFailed& onRegisterFailed)
   {
-    return node_.registerPrefix(prefix, onInterest, onRegisterFailed, flags);
+    return node_.setInterestFilter(prefix, onInterest, onRegisterFailed);
   }
 
   /**
@@ -154,7 +154,7 @@
   void
   unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
   {
-    node_.removeRegisteredPrefix(registeredPrefixId);
+    node_.unsetInterestFilter(registeredPrefixId);
   }
 
   /**
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/face-instance.hpp b/src/management/ndnd-face-instance.hpp
similarity index 95%
rename from src/face-instance.hpp
rename to src/management/ndnd-face-instance.hpp
index 74feee1..03a8589 100644
--- a/src/face-instance.hpp
+++ b/src/management/ndnd-face-instance.hpp
@@ -1,18 +1,18 @@
 /* -*- 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_FACE_INSTANCE_HPP
-#define NDN_FACE_INSTANCE_HPP
+#ifndef NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
+#define NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
 
-#include "encoding/tlv-face-management.hpp"
-#include "name.hpp"
-#include "encoding/block.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.
@@ -339,6 +339,8 @@
   return os;
 }
 
-}
+} // namespace ndnd
+} // namespace ndn
 
-#endif // FACE_INSTANCE
+#endif // NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
+
diff --git a/src/forwarding-entry.hpp b/src/management/ndnd-forwarding-entry.hpp
similarity index 92%
rename from src/forwarding-entry.hpp
rename to src/management/ndnd-forwarding-entry.hpp
index 182dc38..0a02c7e 100644
--- a/src/forwarding-entry.hpp
+++ b/src/management/ndnd-forwarding-entry.hpp
@@ -1,19 +1,20 @@
 /* -*- 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_ENTRY_HPP
-#define NDN_FORWARDING_ENTRY_HPP
+#ifndef NDN_MANAGEMENT_NDND_FORWARDING_ENTRY_HPP
+#define NDN_MANAGEMENT_NDND_FORWARDING_ENTRY_HPP
 
-#include "encoding/tlv-face-management.hpp"
-#include "name.hpp"
-#include "forwarding-flags.hpp"
-#include "encoding/block.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.
@@ -221,6 +222,7 @@
   return os;
 }
 
-}
+} // namespace ndnd
+} // namespace ndn
 
-#endif
+#endif // NDN_MANAGEMENT_NDND_FORWARDING_ENTRY_HPP
diff --git a/src/forwarding-flags.hpp b/src/management/ndnd-forwarding-flags.hpp
similarity index 97%
rename from src/forwarding-flags.hpp
rename to src/management/ndnd-forwarding-flags.hpp
index a0c81c1..8b4ce78 100644
--- a/src/forwarding-flags.hpp
+++ b/src/management/ndnd-forwarding-flags.hpp
@@ -8,10 +8,11 @@
 #ifndef NDN_FORWARDING_FLAGS_HPP
 #define NDN_FORWARDING_FLAGS_HPP
 
-#include "encoding/block.hpp"
-#include "encoding/tlv-face-management.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
@@ -219,6 +220,7 @@
   return os;
 }
 
-}
+} // namespace ndnd
+} // namespace ndn
 
 #endif
diff --git a/src/status-response.hpp b/src/management/ndnd-status-response.hpp
similarity index 87%
rename from src/status-response.hpp
rename to src/management/ndnd-status-response.hpp
index a222951..1543bed 100644
--- a/src/status-response.hpp
+++ b/src/management/ndnd-status-response.hpp
@@ -4,13 +4,14 @@
  * See COPYING for copyright and distribution information.
  */
 
-#ifndef NDN_STATUS_RESPONSE_HPP
-#define NDN_STATUS_RESPONSE_HPP
+#ifndef NDN_MANAGEMENT_NDND_STATUS_RESPONSE_HPP
+#define NDN_MANAGEMENT_NDND_STATUS_RESPONSE_HPP
 
-#include "encoding/block.hpp"
-#include "encoding/tlv-face-management.hpp"
+#include "../encoding/block.hpp"
+#include "../encoding/tlv-face-management.hpp"
 
 namespace ndn {
+namespace ndnd {
 
 class StatusResponse {
 public:
@@ -119,6 +120,7 @@
   return os;
 }
 
-}
+} // namespace ndnd
+} // namespace ndn
 
-#endif // NDN_STATUS_RESPONSE_HPP
+#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
diff --git a/src/node.cpp b/src/node.cpp
index 0c9c872..513c40f 100644
--- a/src/node.cpp
+++ b/src/node.cpp
@@ -9,41 +9,31 @@
 
 #include "node.hpp"
 
-#include "forwarding-entry.hpp"
-#include "face-instance.hpp"
-#include "status-response.hpp"
 #include "security/signature-sha256-with-rsa.hpp"
 
 #include "util/time.hpp"
 #include "util/random.hpp"
-#include "util/ndnd-id-fetcher.hpp"
-
-using namespace std;
-#if NDN_CPP_HAVE_CXX11
-// In the std library, the placeholders are in a different namespace than boost.
-using namespace ndn::func_lib::placeholders;
-#endif
 
 namespace ndn {
 
-Node::Node(const ptr_lib::shared_ptr<Transport>& transport)
+Node::Node(const shared_ptr<Transport>& transport)
   : pitTimeoutCheckTimerActive_(false)
   , transport_(transport)
-  , ndndIdFetcherInterest_(Name("/%C1.M.S.localhost/%C1.M.SRV/ndnd/KEY"), 4000.0)
+  , m_fwController(*this)
 {
-  ioService_ = ptr_lib::make_shared<boost::asio::io_service>();      
-  pitTimeoutCheckTimer_      = ptr_lib::make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
-  processEventsTimeoutTimer_ = ptr_lib::make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
+  ioService_ = make_shared<boost::asio::io_service>();      
+  pitTimeoutCheckTimer_      = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
+  processEventsTimeoutTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
 }
 
-Node::Node(const ptr_lib::shared_ptr<Transport>& transport, const ptr_lib::shared_ptr<boost::asio::io_service> &ioService)
+Node::Node(const shared_ptr<Transport>& transport, const shared_ptr<boost::asio::io_service> &ioService)
   : ioService_(ioService)
   , pitTimeoutCheckTimerActive_(false)
   , transport_(transport)
-  , ndndIdFetcherInterest_(Name("/%C1.M.S.localhost/%C1.M.SRV/ndnd/KEY"), 4000.0)
+  , m_fwController(*this)
 {
-  pitTimeoutCheckTimer_      = ptr_lib::make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
-  processEventsTimeoutTimer_ = ptr_lib::make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
+  pitTimeoutCheckTimer_      = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
+  processEventsTimeoutTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
 }
 
 const PendingInterestId*
@@ -51,27 +41,28 @@
 {
   if (!transport_->isConnected())
     transport_->connect(*ioService_,
-                        ptr_lib::bind(&Node::onReceiveElement, this, _1));
+                        bind(&Node::onReceiveElement, this, _1));
 
-  ptr_lib::shared_ptr<const Interest> interestToExpress(new Interest(interest));
+  shared_ptr<const Interest> interestToExpress(new Interest(interest));
   
-  ioService_->post(func_lib::bind(&Node::asyncExpressInterest, this, interestToExpress, onData, onTimeout));
+  ioService_->post(bind(&Node::asyncExpressInterest, this, interestToExpress, onData, onTimeout));
   
   return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
 }
 
 void
-Node::asyncExpressInterest(const ptr_lib::shared_ptr<const Interest> &interest, const OnData& onData, const OnTimeout& onTimeout)
+Node::asyncExpressInterest(const shared_ptr<const Interest> &interest,
+                           const OnData& onData, const OnTimeout& onTimeout)
 {
-  pendingInterestTable_.push_back(ptr_lib::shared_ptr<PendingInterest>(new PendingInterest
-    (interest, onData, onTimeout)));
+  pendingInterestTable_.push_back(shared_ptr<PendingInterest>(new PendingInterest
+                                                              (interest, onData, onTimeout)));
 
   transport_->send(interest->wireEncode());
 
   if (!pitTimeoutCheckTimerActive_) {
     pitTimeoutCheckTimerActive_ = true;
     pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
-    pitTimeoutCheckTimer_->async_wait(func_lib::bind(&Node::checkPitExpire, this));
+    pitTimeoutCheckTimer_->async_wait(bind(&Node::checkPitExpire, this));
   }
 }
     
@@ -80,7 +71,7 @@
 {
   if (!transport_->isConnected())
     transport_->connect(*ioService_,
-                        ptr_lib::bind(&Node::onReceiveElement, this, _1));
+                        bind(&Node::onReceiveElement, this, _1));
 
   transport_->send(data.wireEncode());
 }
@@ -89,173 +80,52 @@
 void
 Node::removePendingInterest(const PendingInterestId *pendingInterestId)
 {
-  ioService_->post(func_lib::bind(&Node::asyncRemovePendingInterest, this, pendingInterestId));
+  ioService_->post(bind(&Node::asyncRemovePendingInterest, this, pendingInterestId));
 }
 
 
 void
 Node::asyncRemovePendingInterest(const PendingInterestId *pendingInterestId)
 {
-  std::remove_if(pendingInterestTable_.begin(), pendingInterestTable_.end(),
-                 MatchPendingInterestId(pendingInterestId));
+  pendingInterestTable_.remove_if(MatchPendingInterestId(pendingInterestId));
 }
 
 const RegisteredPrefixId*
-Node::registerPrefix
-  (const Name& prefix, const OnInterest& onInterest, const OnRegisterFailed& onRegisterFailed, const ForwardingFlags& flags)
+Node::setInterestFilter(const Name& prefix,
+                        const OnInterest& onInterest,
+                        const OnSetInterestFilterFailed& onSetInterestFilterFailed)
 {
-  ptr_lib::shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
-  
-  if (ndndId_.size() == 0) {
-    // First fetch the ndndId of the connected hub.
-    NdndIdFetcher fetcher(ndndId_,
-                          func_lib::bind(&Node::registerPrefixHelper, this,
-                                         prefixToRegister, onRegisterFailed, flags),
-                          func_lib::bind(onRegisterFailed, prefixToRegister->getPrefix().shared_from_this()));
+  shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
 
-    // @todo: Check if this crash
-    // It is OK for func_lib::function make a copy of the function object because the Info is in a ptr_lib::shared_ptr.
-    expressInterest(ndndIdFetcherInterest_, fetcher, fetcher);
-  }
-  else
-    registerPrefixHelper(prefixToRegister, onRegisterFailed, flags);
+  m_fwController.selfRegisterPrefix(prefixToRegister->getPrefix(),
+                                    bind(&RegisteredPrefixTable::push_back, &registeredPrefixTable_, prefixToRegister),
+                                    bind(onSetInterestFilterFailed, prefixToRegister->getPrefix().shared_from_this()));
   
   return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
 }
 
 void
-Node::removeRegisteredPrefix(const RegisteredPrefixId *registeredPrefixId)
+Node::unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
+{
+  ioService_->post(bind(&Node::asyncUnsetInterestFilter, this, registeredPrefixId));
+}
+
+void
+Node::asyncUnsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
 {
   RegisteredPrefixTable::iterator i = std::find_if(registeredPrefixTable_.begin(), registeredPrefixTable_.end(),
                                                    MatchRegisteredPrefixId(registeredPrefixId));  
   if (i != registeredPrefixTable_.end())
     {
-      ForwardingEntry forwardingEntry("unreg", (*i)->getPrefix(), faceId_);
-      Data data;
-      // This ensures uniqueness of each prefix registration commands
-      data.setName(Name().appendVersion(random::generateWord32()));
-      data.setContent(forwardingEntry.wireEncode());
-        
-      SignatureSha256WithRsa signature;
-      signature.setValue(Block(Tlv::SignatureValue, ptr_lib::make_shared<Buffer>()));
-      data.setSignature(signature);
-
-      // Create an interest where the name has the encoded Data packet.
-      Name interestName;
-      interestName.append("ndnx");
-      interestName.append(ndndId_);
-      interestName.append("unreg");
-      interestName.append(data.wireEncode());
-
-      Interest interest(interestName);
-      interest.setScope(1);
-      interest.setInterestLifetime(1000);
-      interest.setMustBeFresh(true);
-
-      expressInterest(interest, OnData(), OnTimeout());
-        
-      registeredPrefixTable_.erase(i);
+      m_fwController.selfDeregisterPrefix((*i)->getPrefix(),
+                                          bind(&RegisteredPrefixTable::erase, &registeredPrefixTable_, i),
+                                          ndnd::Control::FailCallback());
     }
 
   // there cannot be two registered prefixes with the same id. if there are, then something is broken
 }
 
 void 
-Node::registerPrefixHelper(const ptr_lib::shared_ptr<RegisteredPrefix> &prefixToRegister,
-                           const OnRegisterFailed& onRegisterFailed, 
-                           const ForwardingFlags& flags)
-{
-  // Create a ForwardingEntry.
-
-  // AlexA: ndnd ignores any freshness that is larger than 3600 sec and sets 300 sec instead
-  //        to register "forever" (=2000000000 sec), freshnessPeriod must be omitted
-  ForwardingEntry forwardingEntry("selfreg", prefixToRegister->getPrefix(), -1, flags, -1);
-  Block content = forwardingEntry.wireEncode();
-
-
-  // Set the ForwardingEntry as the content of a Data packet and sign.
-  Data data;
-  // This ensures uniqueness of each prefix registration commands
-  data.setName(Name().appendVersion(random::generateWord32()));
-  data.setContent(content);
-  
-  // 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, ptr_lib::make_shared<Buffer>()));
-  data.setSignature(signature);
-
-  // Create an interest where the name has the encoded Data packet.
-  Name interestName;
-  interestName.append("ndnx");
-  interestName.append(ndndId_);
-  interestName.append("selfreg");
-  interestName.append(data.wireEncode());
-
-  Interest interest(interestName);
-  interest.setScope(1);
-  interest.setInterestLifetime(1000);
-  interest.setMustBeFresh(true);
-
-  expressInterest(interest,
-                  func_lib::bind(&Node::registerPrefixFinal, this,
-                                 prefixToRegister, onRegisterFailed, _1, _2),
-                  func_lib::bind(onRegisterFailed, prefixToRegister->getPrefix().shared_from_this()));
-}
-
-void
-Node::registerPrefixFinal(const ptr_lib::shared_ptr<RegisteredPrefix> &prefixToRegister,
-                          const OnRegisterFailed& onRegisterFailed,
-                          const ptr_lib::shared_ptr<const Interest>&, const ptr_lib::shared_ptr<Data>&data)
-{
-  Block content = data->getContent();
-  content.parse();
-
-  if (content.getAll().empty())
-    {
-      onRegisterFailed(prefixToRegister->getPrefix().shared_from_this());
-      return;
-    }
-
-  Block::element_iterator val = content.getAll().begin();
-  
-  switch(val->type())
-    {
-    case Tlv::FaceManagement::ForwardingEntry:
-      {
-        ForwardingEntry entry;
-        entry.wireDecode(*val);
-
-        // Save the onInterest callback and send the registration interest.
-        registeredPrefixTable_.push_back(prefixToRegister);
-
-        /// @todo Notify user about successful registration
-        
-        // succeeded
-        return;
-      }
-    case Tlv::FaceManagement::StatusResponse:
-      {
-        // failed :(
-        StatusResponse resp;
-        resp.wireDecode(*val);
-
-        // std::cerr << "StatusReponse: " << resp << std::endl;
-      
-        onRegisterFailed(prefixToRegister->getPrefix().shared_from_this());
-        return;
-      }
-    default:
-      {
-        // failed :(
-      
-        onRegisterFailed(prefixToRegister->getPrefix().shared_from_this());
-        return;
-      }
-    }
-}
-
-void 
 Node::processEvents(Milliseconds timeout/* = 0 */, bool keepThread/* = false*/)
 {
   try
@@ -275,7 +145,7 @@
       
       if (keepThread) {
         // work will ensure that ioService_ is running until work object exists
-        ioServiceWork_ = ptr_lib::make_shared<boost::asio::io_service::work>(boost::ref(*ioService_));
+        ioServiceWork_ = make_shared<boost::asio::io_service::work>(boost::ref(*ioService_));
       }
           
       ioService_->run();
@@ -295,6 +165,18 @@
     }
 }
 
+void 
+Node::shutdown()
+{
+  pendingInterestTable_.clear();
+  registeredPrefixTable_.clear();
+
+  transport_->close();
+  pitTimeoutCheckTimer_->cancel();
+  processEventsTimeoutTimer_->cancel();
+  pitTimeoutCheckTimerActive_ = false;
+}
+
 void
 Node::fireProcessEventsTimeout(const boost::system::error_code& error)
 {
@@ -306,24 +188,29 @@
 Node::checkPitExpire()
 {
   // Check for PIT entry timeouts.  Go backwards through the list so we can erase entries.
-  MillisecondsSince1970 nowMilliseconds = ndn_getNowMilliseconds();
-  for (int i = (int)pendingInterestTable_.size() - 1; i >= 0; --i) {
-    if (pendingInterestTable_[i]->isTimedOut(nowMilliseconds)) {
-      // Save the PendingInterest and remove it from the PIT.  Then call the callback.
-      ptr_lib::shared_ptr<PendingInterest> pendingInterest = pendingInterestTable_[i];
-      pendingInterestTable_.erase(pendingInterestTable_.begin() + i);
-      pendingInterest->callTimeout();
-      
-      // Refresh now since the timeout callback might have delayed.
-      nowMilliseconds = ndn_getNowMilliseconds();
+  MillisecondsSince1970 nowMilliseconds = getNowMilliseconds();
+
+  PendingInterestTable::iterator i = pendingInterestTable_.begin();
+  while (i != pendingInterestTable_.end())
+    {
+      if ((*i)->isTimedOut(nowMilliseconds))
+        {
+          // Save the PendingInterest and remove it from the PIT.  Then call the callback.
+          shared_ptr<PendingInterest> pendingInterest = *i;
+
+          i = pendingInterestTable_.erase(i);
+
+          pendingInterest->callTimeout();
+        }
+      else
+        ++i;
     }
-  }
 
   if (!pendingInterestTable_.empty()) {
     pitTimeoutCheckTimerActive_ = true;
     
     pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
-    pitTimeoutCheckTimer_->async_wait(func_lib::bind(&Node::checkPitExpire, this));
+    pitTimeoutCheckTimer_->async_wait(bind(&Node::checkPitExpire, this));
   }
   else {
     pitTimeoutCheckTimerActive_ = false;
@@ -343,7 +230,7 @@
 {
   if (block.type() == Tlv::Interest)
     {
-      ptr_lib::shared_ptr<Interest> interest(new Interest());
+      shared_ptr<Interest> interest(new Interest());
       interest->wireDecode(block);
     
       RegisteredPrefixTable::iterator entry = getEntryForRegisteredPrefix(interest->getName());
@@ -353,14 +240,14 @@
     }
   else if (block.type() == Tlv::Data)
     {
-      ptr_lib::shared_ptr<Data> data(new Data());
+      shared_ptr<Data> data(new Data());
       data->wireDecode(block);
 
       PendingInterestTable::iterator entry = getEntryIndexForExpressedInterest(data->getName());
       if (entry != pendingInterestTable_.end()) {
         // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
         const OnData onData = (*entry)->getOnData();
-        const ptr_lib::shared_ptr<const Interest> interest = (*entry)->getInterest();
+        const shared_ptr<const Interest> interest = (*entry)->getInterest();
         pendingInterestTable_.erase(entry);
 
         if (onData) {
@@ -374,18 +261,6 @@
     }
 }
 
-void 
-Node::shutdown()
-{
-  pendingInterestTable_.clear();
-  registeredPrefixTable_.clear();
-
-  transport_->close();
-  pitTimeoutCheckTimer_->cancel();
-  processEventsTimeoutTimer_->cancel();
-  pitTimeoutCheckTimerActive_ = false;
-}
-
 Node::PendingInterestTable::iterator 
 Node::getEntryIndexForExpressedInterest(const Name& name)
 {
@@ -419,28 +294,4 @@
   return longestPrefix;
 }
 
-Node::PendingInterest::PendingInterest(const ptr_lib::shared_ptr<const Interest>& interest,
-                                       const OnData& onData, const OnTimeout& onTimeout)
-: interest_(interest),
-  onData_(onData), onTimeout_(onTimeout)
-{
-  // Set up timeoutTime_.
-  if (interest_->getInterestLifetime() >= 0)
-    timeoutTimeMilliseconds_ = ndn_getNowMilliseconds() + interest_->getInterestLifetime();
-  else
-    // No timeout.
-    /**
-     * @todo Set more meaningful default timeout.  This timeout MUST exist.
-     */
-    timeoutTimeMilliseconds_ = ndn_getNowMilliseconds() + 4000;
-}
-
-void 
-Node::PendingInterest::callTimeout()
-{
-  if (onTimeout_) {
-    onTimeout_(interest_);
-  }
-}
-
-}
+} // namespace ndn
diff --git a/src/node.hpp b/src/node.hpp
index 6dc1954..726b4c1 100644
--- a/src/node.hpp
+++ b/src/node.hpp
@@ -11,9 +11,13 @@
 #include "common.hpp"
 #include "interest.hpp"
 #include "data.hpp"
-#include "forwarding-flags.hpp"
 #include "transport/transport.hpp"
 
+#include "management/ndnd-control.hpp"
+
+#include "detail/registered-prefix.hpp"
+#include "detail/pending-interest.hpp"
+
 namespace ndn {
 
 struct PendingInterestId;
@@ -22,26 +26,24 @@
 /**
  * An OnData function object is used to pass a callback to expressInterest.
  */
-typedef func_lib::function<void(const ptr_lib::shared_ptr<const Interest>&, const ptr_lib::shared_ptr<Data>&)> OnData;
+typedef function<void(const shared_ptr<const Interest>&, const shared_ptr<Data>&)> OnData;
 
 /**
  * An OnTimeout function object is used to pass a callback to expressInterest.
  */
-typedef func_lib::function<void(const ptr_lib::shared_ptr<const Interest>&)> OnTimeout;
+typedef function<void(const shared_ptr<const Interest>&)> OnTimeout;
 
 /**
  * An OnInterest function object is used to pass a callback to registerPrefix.
  */
-typedef func_lib::function<void
-  (const ptr_lib::shared_ptr<const Name>&, const ptr_lib::shared_ptr<const Interest>&)> OnInterest;
+typedef function<void
+  (const shared_ptr<const Name>&, const shared_ptr<const Interest>&)> OnInterest;
 
 /**
  * An OnRegisterFailed function object is used to report when registerPrefix fails.
  */
-typedef func_lib::function<void(const ptr_lib::shared_ptr<const Name>&)> OnRegisterFailed;
+typedef function<void(const shared_ptr<const Name>&)> OnSetInterestFilterFailed;
 
-class Face;
-    
 class Node {
 public:
   struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
@@ -51,7 +53,7 @@
    * @param transport A shared_ptr to a Transport object used for communication.
    * @param transport A shared_ptr to a Transport::ConnectionInfo to be used to connect to the transport.
    */
-  Node(const ptr_lib::shared_ptr<Transport>& transport);
+  Node(const shared_ptr<Transport>& transport);
 
   /**
    * @brief Alternative (special use case) version of the constructor, can be used to aggregate
@@ -65,16 +67,16 @@
    *     face1.processEvents();
    * </code>
    */
-  Node(const ptr_lib::shared_ptr<Transport>& transport, const ptr_lib::shared_ptr<boost::asio::io_service> &ioService);
+  Node(const shared_ptr<Transport>& transport, const shared_ptr<boost::asio::io_service> &ioService);
   
   /**
-   * Send the Interest through the transport, read the entire response and call onData(interest, data).
-   * @param interest A reference to the Interest.  This copies the Interest.
-   * @param onData A function object to call when a matching data packet is received.  This copies the function object, so you may need to
-   * use func_lib::ref() as appropriate.
-   * @param onTimeout A function object to call if the interest times out.  If onTimeout is an empty OnTimeout(), this does not use it.
-   * This copies the function object, so you may need to use func_lib::ref() as appropriate.
-   * @param wireFormat A WireFormat object used to encode the message.
+   * @brief Send the Interest through the transport, read the entire response and call onData(interest, data).
+   *
+   * @param interest  A reference to the Interest.  This copies the Interest.
+   * @param onData    A function object to call when a matching data packet is received.
+   * @param onTimeout A function object to call if the interest times out.
+   *                  If onTimeout is an empty OnTimeout(), this does not use it.
+   *
    * @return The pending interest ID which can be used with removePendingInterest.
    */
   const PendingInterestId*
@@ -93,16 +95,16 @@
    * Register prefix with the connected NDN hub and call onInterest when a matching interest is received.
    * @param prefix A reference to a Name for the prefix to register.  This copies the Name.
    * @param onInterest A function object to call when a matching interest is received.  This copies the function object, so you may need to
-   * use func_lib::ref() as appropriate.
+   * use ref() as appropriate.
    * @param onRegisterFailed A function object to call if failed to retrieve the connected hub’s ID or failed to register the prefix.
    * This calls onRegisterFailed(prefix) where prefix is the prefix given to registerPrefix.
    * @param flags The flags for finer control of which interests are forward to the application.
-   * @param wireFormat A WireFormat object used to encode the message.
    * @return The registered prefix ID which can be used with removeRegisteredPrefix.
    */
   const RegisteredPrefixId*
-  registerPrefix
-    (const Name& prefix, const OnInterest& onInterest, const OnRegisterFailed& onRegisterFailed, const ForwardingFlags& flags);
+  setInterestFilter(const Name& prefix,
+                    const OnInterest& onInterest,
+                    const OnSetInterestFilterFailed& onSetInterestFilterFailed);
 
   /**
    * Remove the registered prefix entry with the registeredPrefixId from the pending interest table.  
@@ -111,7 +113,7 @@
    * @param registeredPrefixId The ID returned from registerPrefix.
    */
   void
-  removeRegisteredPrefix(const RegisteredPrefixId *registeredPrefixId);
+  unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId);
 
    /**
    * @brief Publish data packet
@@ -140,10 +142,7 @@
    */
   void 
   processEvents(Milliseconds timeout = 0, bool keepThread = false);
-  
-  const ptr_lib::shared_ptr<Transport>& 
-  getTransport() { return transport_; }
-  
+
   void 
   shutdown();
 
@@ -151,133 +150,27 @@
   ioService() { return ioService_; }
 
 private:
+  struct ProcessEventsTimeout {};
+  typedef std::list<shared_ptr<PendingInterest> > PendingInterestTable;
+  typedef std::list<shared_ptr<RegisteredPrefix> > RegisteredPrefixTable;
+  
   void
-  asyncExpressInterest(const ptr_lib::shared_ptr<const Interest> &interest,
+  asyncExpressInterest(const shared_ptr<const Interest> &interest,
                        const OnData& onData, const OnTimeout& onTimeout);
 
   void
   asyncRemovePendingInterest(const PendingInterestId *pendingInterestId);
+
+  void
+  asyncUnsetInterestFilter(const RegisteredPrefixId *registeredPrefixId);
   
   void 
   onReceiveElement(const Block &wire);
 
-  struct ProcessEventsTimeout {};  
+  
   static void
   fireProcessEventsTimeout(const boost::system::error_code& error);
 
-private:
-  class PendingInterest {
-  public:
-    /**
-     * Create a new PitEntry and set the timeoutTime_ based on the current time and the interest lifetime.
-     * @param interest A shared_ptr for the interest.
-     * @param onData A function object to call when a matching data packet is received.
-     * @param onTimeout A function object to call if the interest times out.  If onTimeout is an empty OnTimeout(), this does not use it.
-     */
-    PendingInterest
-      (const ptr_lib::shared_ptr<const Interest>& interest, const OnData& onData, 
-       const OnTimeout& onTimeout);
-    
-    const ptr_lib::shared_ptr<const Interest>& 
-    getInterest() { return interest_; }
-    
-    const OnData& 
-    getOnData() { return onData_; }
-    
-    /**
-     * Check if this interest is timed out.
-     * @param nowMilliseconds The current time in milliseconds from ndn_getNowMilliseconds.
-     * @return true if this interest timed out, otherwise false.
-     */
-    bool 
-    isTimedOut(MillisecondsSince1970 nowMilliseconds)
-    {
-      return timeoutTimeMilliseconds_ >= 0.0 && nowMilliseconds >= timeoutTimeMilliseconds_;
-    }
-
-    /**
-     * Call onTimeout_ (if defined).  This ignores exceptions from the onTimeout_.
-     */
-    void 
-    callTimeout();
-    
-  private:
-    ptr_lib::shared_ptr<const Interest> interest_;
-    const OnData onData_;
-    const OnTimeout onTimeout_;
-    
-    MillisecondsSince1970 timeoutTimeMilliseconds_; /**< The time when the interest times out in milliseconds according to ndn_getNowMilliseconds, or -1 for no timeout. */
-  };
-
-  // Functor to match pending interests against PendingInterestId
-  struct MatchPendingInterestId
-  {
-    MatchPendingInterestId(const PendingInterestId *pendingInterestId)
-      : id_(pendingInterestId)
-    {
-    }
-
-    bool
-    operator()(const ptr_lib::shared_ptr<const PendingInterest> &pendingInterest) const
-    {
-      return (reinterpret_cast<const PendingInterestId *>(pendingInterest.get()) == id_);
-    }
-  private:
-    const PendingInterestId *id_;
-  };
-
-  
-  class RegisteredPrefix {
-  public:
-    /**
-     * Create a new PrefixEntry.
-     * @param prefix A shared_ptr for the prefix.
-     * @param onInterest A function object to call when a matching data packet is received.
-     */
-    RegisteredPrefix(const Name& prefix, const OnInterest& onInterest)
-      : prefix_(new Name(prefix))
-      , onInterest_(onInterest)
-    {
-    }
-    
-    const Name& 
-    getPrefix() const
-    {
-      return *prefix_;
-    }
-    
-    const OnInterest& 
-    getOnInterest() const
-    {
-      return onInterest_;
-    }
-    
-  private:
-    ptr_lib::shared_ptr<Name> prefix_;
-    const OnInterest onInterest_;
-  };
-
-  // Functor to match pending interests against PendingInterestId
-  struct MatchRegisteredPrefixId
-  {
-    MatchRegisteredPrefixId(const RegisteredPrefixId *registeredPrefixId)
-      : id_(registeredPrefixId)
-    {
-    }
-
-    bool
-    operator()(const ptr_lib::shared_ptr<RegisteredPrefix> &registeredPrefix) const
-    {
-      return (reinterpret_cast<const RegisteredPrefixId *>(registeredPrefix.get()) == id_);
-    }
-  private:
-    const RegisteredPrefixId *id_;
-  };
-
-  
-  typedef std::vector<ptr_lib::shared_ptr<PendingInterest> > PendingInterestTable;
-  typedef std::vector<ptr_lib::shared_ptr<RegisteredPrefix> > RegisteredPrefixTable;
-  
   /**
    * Find the entry from the pit_ where the name conforms to the entry's interest selectors, and
    * the entry interest name is the longest that matches name.
@@ -295,48 +188,23 @@
   RegisteredPrefixTable::iterator
   getEntryForRegisteredPrefix(const Name& name);
 
-  /**
-   * Do the work of registerPrefix once we know we are connected with an ndndId_.
-   * @param registeredPrefixId The PrefixEntry::getNextRegisteredPrefixId() which registerPrefix got so it could return it to the caller.
-   * @param prefix
-   * @param onInterest
-   * @param onRegisterFailed
-   * @param flags
-   * @param wireFormat
-   */  
-  void 
-  registerPrefixHelper
-    (const ptr_lib::shared_ptr<RegisteredPrefix> &prefixToRegister, 
-     const OnRegisterFailed& onRegisterFailed, const ForwardingFlags& flags);
-
-  /**
-   * @brief Final stage of prefix registration, invoked when registration succeeded
-   *
-   * This method actually sets entry in a local interest filter table
-   */
-  void
-  registerPrefixFinal(const ptr_lib::shared_ptr<RegisteredPrefix> &prefixToRegister,
-                      const OnRegisterFailed& onRegisterFailed,
-                      const ptr_lib::shared_ptr<const Interest>&, const ptr_lib::shared_ptr<Data>&);
   
   void
   checkPitExpire();
   
 private:
-  ptr_lib::shared_ptr<boost::asio::io_service> ioService_;
-  ptr_lib::shared_ptr<boost::asio::io_service::work> ioServiceWork_; // needed if thread needs to be preserved
-  ptr_lib::shared_ptr<boost::asio::deadline_timer> pitTimeoutCheckTimer_;
+  shared_ptr<boost::asio::io_service> ioService_;
+  shared_ptr<boost::asio::io_service::work> ioServiceWork_; // needed if thread needs to be preserved
+  shared_ptr<boost::asio::deadline_timer> pitTimeoutCheckTimer_;
   bool pitTimeoutCheckTimerActive_;
-  ptr_lib::shared_ptr<boost::asio::deadline_timer> processEventsTimeoutTimer_;
+  shared_ptr<boost::asio::deadline_timer> processEventsTimeoutTimer_;
   
-  ptr_lib::shared_ptr<Transport> transport_;
+  shared_ptr<Transport> transport_;
 
   PendingInterestTable pendingInterestTable_;
   RegisteredPrefixTable registeredPrefixTable_;
-  Interest ndndIdFetcherInterest_;
 
-  int64_t faceId_; // internal face ID (needed for prefix de-registration)
-  Buffer ndndId_;
+  ndnd::Control m_fwController;
 };
 
 } // namespace ndn
diff --git a/src/util/ndnd-id-fetcher.hpp b/src/util/ndnd-id-fetcher.hpp
deleted file mode 100644
index da8c35e..0000000
--- a/src/util/ndnd-id-fetcher.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -*- 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_NDND_ID_FETCHER_HPP
-#define NDN_NDND_ID_FETCHER_HPP
-
-#include "../common.hpp"
-#include "crypto.hpp"
-
-namespace ndn {
-
-/**
- * An NdndIdFetcher receives the Data packet with the publisher public key digest for the connected NDN hub.
- * This class is a function object for the callbacks. It only holds a pointer to an Info object, so it is OK to copy the pointer.
- */
-class NdndIdFetcher {
-public:
-  typedef func_lib::function<void (void)> OnSuccess;
-  typedef func_lib::function<void (void)> OnFailure;
-  
-  
-  class Info;
-  NdndIdFetcher(Buffer &ndndId, const OnSuccess& onSuccess, const OnFailure& onFailure)
-    : ndndId_(ndndId)
-    , onSuccess_(onSuccess)
-    , onFailure_(onFailure)
-  {
-  }
-    
-  /**
-   * We received the ndnd ID.
-   * @param interest
-   * @param data
-   */
-  inline void 
-  operator()(const ptr_lib::shared_ptr<const Interest>& interest, const ptr_lib::shared_ptr<Data>& ndndIdData);
-
-  /**
-   * We timed out fetching the ndnd ID.
-   * @param interest
-   */
-  inline void 
-  operator()(const ptr_lib::shared_ptr<const Interest>& timedOutInterest);
-
-private:
-  Buffer &ndndId_;
-  OnSuccess onSuccess_;
-  OnFailure onFailure_;
-};
-
-void 
-NdndIdFetcher::operator()(const ptr_lib::shared_ptr<const Interest>& interest, const ptr_lib::shared_ptr<Data>& ndndIdData)
-{
-  if (ndndIdData->getSignature().getType() == Signature::Sha256WithRsa)
-    {
-      ndndId_.resize(32);
-      ndn_digestSha256(ndndIdData->getContent().value(), ndndIdData->getContent().value_size(), ndndId_.buf());
-      onSuccess_();
-    }
-  else
-    onFailure_();
-}
-
-void 
-NdndIdFetcher::operator()(const ptr_lib::shared_ptr<const Interest>& timedOutInterest)
-{
-  onFailure_();
-}
-
-
-} // namespace ndn
-
-#endif // NDN_NDND_ID_FETCHER_HPP
diff --git a/tests/main.cpp b/tests/main.cpp
index 6b0a14a..d43aa5a 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -1,10 +1,6 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
  */
 
 #define BOOST_TEST_MAIN 1
diff --git a/tests/test-encode-decode-forwarding-entry.cpp b/tests/management/test-ndnd-forwarding-entry.cpp
similarity index 90%
rename from tests/test-encode-decode-forwarding-entry.cpp
rename to tests/management/test-ndnd-forwarding-entry.cpp
index 89c0d46..bd5aa9f 100644
--- a/tests/test-encode-decode-forwarding-entry.cpp
+++ b/tests/management/test-ndnd-forwarding-entry.cpp
@@ -6,7 +6,7 @@
 
 #include <boost/test/unit_test.hpp>
 
-#include "forwarding-entry.hpp"
+#include "management/ndnd-forwarding-entry.hpp"
 
 #if __clang__
 #pragma clang diagnostic push
@@ -18,6 +18,7 @@
 
 using namespace std;
 namespace ndn {
+namespace ndnd {
 
 const uint8_t FORWARDING_ENTRY[] = {0x81, 0x19, 0x83, 0x07, 0x73, 0x65, 0x6c, 0x66, 0x72, 0x65, 0x67, 0x03, 0x0b, 0x04, 0x01, 0x61, 0x04, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x8a, 0x01, 0x03};
 
@@ -25,7 +26,7 @@
 
 BOOST_AUTO_TEST_CASE (Encode)
 {
-  ndn::ForwardingEntry forwardingEntry("selfreg", "/a/prefix", -1, ForwardingFlags(), -1);
+  ForwardingEntry forwardingEntry("selfreg", "/a/prefix", -1, ForwardingFlags(), -1);
   const Block &wire = forwardingEntry.wireEncode();
 
   BOOST_REQUIRE_EQUAL_COLLECTIONS(FORWARDING_ENTRY, FORWARDING_ENTRY+sizeof(FORWARDING_ENTRY),
@@ -34,7 +35,7 @@
 
 BOOST_AUTO_TEST_CASE (Decode)
 {
-  ndn::ForwardingEntry forwardingEntry;
+  ForwardingEntry forwardingEntry;
   
   BOOST_REQUIRE_NO_THROW(forwardingEntry.wireDecode(Block(FORWARDING_ENTRY, sizeof(FORWARDING_ENTRY))));
 
@@ -54,4 +55,5 @@
 
 BOOST_AUTO_TEST_SUITE_END()
 
+} // namespace ndnd
 } // namespace ndn
diff --git a/tests/test-nfd-control.cpp b/tests/management/test-nfd-control.cpp
similarity index 100%
rename from tests/test-nfd-control.cpp
rename to tests/management/test-nfd-control.cpp
diff --git a/tests/test-all.hpp b/tests/test-all.hpp
new file mode 100644
index 0000000..0e4c8c5
--- /dev/null
+++ b/tests/test-all.hpp
@@ -0,0 +1,11 @@
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_TEST_ALL_HPP
+#define NDN_TEST_ALL_HPP
+
+#include "common.hpp"
+
+#endif
diff --git a/tests/test-encode-decode-block.cpp b/tests/test-encode-decode-block.cpp
index fe433a4..9e5e01c 100644
--- a/tests/test-encode-decode-block.cpp
+++ b/tests/test-encode-decode-block.cpp
@@ -1,6 +1,5 @@
 /**
  * Copyright (C) 2013 Regents of the University of California.
- * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  * See COPYING for copyright and distribution information.
  */
 
diff --git a/tests/test-encode-decode-data.cpp b/tests/test-encode-decode-data.cpp
index 0e13d75..239778b 100644
--- a/tests/test-encode-decode-data.cpp
+++ b/tests/test-encode-decode-data.cpp
@@ -1,6 +1,5 @@
 /**
  * Copyright (C) 2013 Regents of the University of California.
- * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  * See COPYING for copyright and distribution information.
  */
 
diff --git a/tests/test-encode-decode-interest.cpp b/tests/test-encode-decode-interest.cpp
index 09057fb..4c6daaa 100644
--- a/tests/test-encode-decode-interest.cpp
+++ b/tests/test-encode-decode-interest.cpp
@@ -1,6 +1,5 @@
 /**
  * Copyright (C) 2013 Regents of the University of California.
- * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  * See COPYING for copyright and distribution information.
  */
 
diff --git a/tests/test-exclude.cpp b/tests/test-exclude.cpp
index 6f7f306..033fdea 100644
--- a/tests/test-exclude.cpp
+++ b/tests/test-exclude.cpp
@@ -1,11 +1,6 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Alexander Afanasyev
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
  */
 
 #include "exclude.hpp"
diff --git a/tests/test-faces.cpp b/tests/test-faces.cpp
index 67c5add..498ca73 100644
--- a/tests/test-faces.cpp
+++ b/tests/test-faces.cpp
@@ -1,6 +1,5 @@
 /**
  * Copyright (C) 2013 Regents of the University of California.
- * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  * See COPYING for copyright and distribution information.
  */
 
diff --git a/tests/test-name.cpp b/tests/test-name.cpp
index a4e86d0..b6501d6 100644
--- a/tests/test-name.cpp
+++ b/tests/test-name.cpp
@@ -1,6 +1,5 @@
 /**
  * Copyright (C) 2013 Regents of the University of California.
- * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  * See COPYING for copyright and distribution information.
  */
 
diff --git a/tests/wscript b/tests/wscript
index 4fbfb4a..8a5de6e 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -21,5 +21,5 @@
     unittests.source += bld.path.ant_glob('**/*-sqlite3.cpp')
 
     if bld.env['WITH_PCH']:
-        unittests.pch = "../src/common.hpp"
+        unittests.pch = "test-all.hpp"