face+node: Improving async operations

Now expressInterest is executed strictly in io_service thread, which
should guarantee absence of resource contention, provided that
io_service has exactly one thread.

Instead of numerical IDs for expressed Interests and registered
prefixes, an opaque PendingInterestId and RegisteredPrefixId classed are
used.  These classes are basically reinterpret_cast pointers to the
PendingInterest and RegisteredPrefix objects stored on the node.

refs #1142 (http://redmine.named-data.net/issues/1142)

Change-Id: I4b146ee34b98bfa6564935d5f2fe33056a402694
diff --git a/include/ndn-cpp-dev/common.hpp b/include/ndn-cpp-dev/common.hpp
index 59c49b5..a651a40 100644
--- a/include/ndn-cpp-dev/common.hpp
+++ b/include/ndn-cpp-dev/common.hpp
@@ -32,6 +32,7 @@
 
 // #if NDN_CPP_HAVE_BOOST_SHARED_PTR
 #include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
 #include <boost/make_shared.hpp>
 namespace ndn { namespace ptr_lib = boost; }
 
@@ -63,6 +64,7 @@
 (unset LANG; find . -type f -exec sed -i '' 's/ mpl_/ ndnboost_mpl_/g' {} +)
  */
 #include <ndnboost/shared_ptr.hpp>
+#include <ndnboost/enable_shared_from_this.hpp>
 #include <ndnboost/make_shared.hpp>
 namespace ndn { namespace ptr_lib = ndnboost; }
 
diff --git a/include/ndn-cpp-dev/face.hpp b/include/ndn-cpp-dev/face.hpp
index e006458..ec4fe27 100644
--- a/include/ndn-cpp-dev/face.hpp
+++ b/include/ndn-cpp-dev/face.hpp
@@ -20,22 +20,38 @@
 class Face {
 public:
   /**
-   * Create a new Face for communication with an NDN hub at host:port using the default TcpTransport.
-   * @param host The host of the NDN hub.
-   * @param port The port of the NDN hub. If omitted. use 6363.
+   * @brief Create a new Face for communication with an NDN hub using the default TcpTransport.
    */
   Face()
-  : node_(ptr_lib::shared_ptr<UnixTransport>(new UnixTransport()))
+    : node_(ptr_lib::shared_ptr<UnixTransport>(new UnixTransport()))
+  {
+  }
+
+  /**
+   * @brief Create a new Face for communication with an NDN hub using the default Transport.
+   * @param ioService A shared pointer to boost::io_service object that should control all IO operations
+   */
+  Face(const ptr_lib::shared_ptr<boost::asio::io_service> &ioService)
+    : node_(ptr_lib::shared_ptr<UnixTransport>(new UnixTransport()), ioService)
+  {
+  }
+  
+  /**
+   * Create a new Face for communication with an NDN hub with the given Transport object and connectionInfo.
+   * @param transport A shared_ptr to a Transport object used for communication.
+   */
+  Face(const ptr_lib::shared_ptr<Transport>& transport)
+    : node_(transport)
   {
   }
 
   /**
    * Create a new Face for communication with an NDN hub with the given Transport object and connectionInfo.
    * @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.
+   * @param ioService A shared pointer to boost::io_service object that should control all IO operations
    */
-  Face(const ptr_lib::shared_ptr<Transport>& transport)
-  : node_(transport)
+  Face(const ptr_lib::shared_ptr<Transport>& transport, const ptr_lib::shared_ptr<boost::asio::io_service> &ioService)
+    : node_(transport, ioService)
   {
   }
   
@@ -56,10 +72,9 @@
    * 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. If omitted, use WireFormat getDefaultWireFormat().
    * @return The pending interest ID which can be used with removePendingInterest.
    */
-  uint64_t 
+  const PendingInterestId*
   expressInterest
     (const Interest& interest, const OnData& onData, const OnTimeout& onTimeout = OnTimeout())
   {
@@ -72,13 +87,11 @@
    * @param name A reference to a Name for the interest.  This copies the Name.
    * @param interestTemplate if not 0, copy interest selectors from the template.   This does not keep a pointer to the Interest object.
    * @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.
+   *        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. If omitted, use WireFormat getDefaultWireFormat().
-   * @return The pending interest ID which can be used with removePendingInterest.
+   *        This copies the function object, so you may need to use func_lib::ref() as appropriate.
    */
-  uint64_t 
+  const PendingInterestId*
   expressInterest
     (const Name& name, const Interest *interestTemplate, const OnData& onData, const OnTimeout& onTimeout = OnTimeout());
 
@@ -93,7 +106,7 @@
    * @param wireFormat A WireFormat object used to encode the message. If omitted, use WireFormat getDefaultWireFormat().
    * @return The pending interest ID which can be used with removePendingInterest.
    */
-  uint64_t 
+  const PendingInterestId*
   expressInterest
     (const Name& name, const OnData& onData, const OnTimeout& onTimeout = OnTimeout()) 
   {
@@ -107,7 +120,7 @@
    * @param pendingInterestId The ID returned from expressInterest.
    */
   void
-  removePendingInterest(uint64_t pendingInterestId)
+  removePendingInterest(const PendingInterestId* pendingInterestId)
   {
     node_.removePendingInterest(pendingInterestId);
   }
@@ -124,7 +137,7 @@
    * @param wireFormat A WireFormat object used to encode the message. If omitted, use WireFormat getDefaultWireFormat().
    * @return The registered prefix ID which can be used with removeRegisteredPrefix.
    */
-  uint64_t 
+  const RegisteredPrefixId*
   setInterestFilter
     (const Name& prefix, const OnInterest& onInterest, const OnRegisterFailed& onRegisterFailed, const ForwardingFlags& flags = ForwardingFlags())
   {
@@ -138,7 +151,7 @@
    * @param registeredPrefixId The ID returned from registerPrefix.
    */
   void
-  unsetInterestFilter(uint64_t registeredPrefixId)
+  unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
   {
     node_.removeRegisteredPrefix(registeredPrefixId);
   }
diff --git a/include/ndn-cpp-dev/name.hpp b/include/ndn-cpp-dev/name.hpp
index ebac18f..1603618 100644
--- a/include/ndn-cpp-dev/name.hpp
+++ b/include/ndn-cpp-dev/name.hpp
@@ -21,7 +21,7 @@
 /**
  * A Name holds an array of Name::Component and represents an NDN name.
  */
-class Name {
+class Name : public ptr_lib::enable_shared_from_this<Name> {
 public:
   /**
    * A Name::Component holds a read-only name component value.
diff --git a/include/ndn-cpp-dev/node.hpp b/include/ndn-cpp-dev/node.hpp
index b5e4e97..7892075 100644
--- a/include/ndn-cpp-dev/node.hpp
+++ b/include/ndn-cpp-dev/node.hpp
@@ -14,9 +14,11 @@
 #include "forwarding-flags.hpp"
 #include "transport/transport.hpp"
 
-
 namespace ndn {
 
+struct PendingInterestId;
+struct RegisteredPrefixId;
+
 /**
  * An OnData function object is used to pass a callback to expressInterest.
  */
@@ -31,7 +33,7 @@
  * 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>&, Transport&, uint64_t)> OnInterest;
+  (const ptr_lib::shared_ptr<const Name>&, const ptr_lib::shared_ptr<const Interest>&)> OnInterest;
 
 /**
  * An OnRegisterFailed function object is used to report when registerPrefix fails.
@@ -75,7 +77,7 @@
    * @param wireFormat A WireFormat object used to encode the message.
    * @return The pending interest ID which can be used with removePendingInterest.
    */
-  uint64_t 
+  const PendingInterestId*
   expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout);
   
   /**
@@ -85,7 +87,7 @@
    * @param pendingInterestId The ID returned from expressInterest.
    */
   void
-  removePendingInterest(uint64_t pendingInterestId);
+  removePendingInterest(const PendingInterestId *pendingInterestId);
   
   /**
    * Register prefix with the connected NDN hub and call onInterest when a matching interest is received.
@@ -98,7 +100,7 @@
    * @param wireFormat A WireFormat object used to encode the message.
    * @return The registered prefix ID which can be used with removeRegisteredPrefix.
    */
-  uint64_t 
+  const RegisteredPrefixId*
   registerPrefix
     (const Name& prefix, const OnInterest& onInterest, const OnRegisterFailed& onRegisterFailed, const ForwardingFlags& flags);
 
@@ -109,7 +111,7 @@
    * @param registeredPrefixId The ID returned from registerPrefix.
    */
   void
-  removeRegisteredPrefix(uint64_t registeredPrefixId);
+  removeRegisteredPrefix(const RegisteredPrefixId *registeredPrefixId);
 
    /**
    * @brief Publish data packet
@@ -146,6 +148,13 @@
   shutdown();
 
 private:
+  void
+  asyncExpressInterest(const ptr_lib::shared_ptr<const Interest> &interest,
+                       const OnData& onData, const OnTimeout& onTimeout);
+
+  void
+  asyncRemovePendingInterest(const PendingInterestId *pendingInterestId);
+  
   void 
   onReceiveElement(const Block &wire);
 
@@ -158,30 +167,14 @@
   public:
     /**
      * Create a new PitEntry and set the timeoutTime_ based on the current time and the interest lifetime.
-     * @param pendingInterestId A unique ID for this entry, which you should get with getNextPendingInteresId().
      * @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
-      (uint64_t pendingInterestId, const ptr_lib::shared_ptr<const Interest>& interest, const OnData& onData, 
+      (const ptr_lib::shared_ptr<const Interest>& interest, const OnData& onData, 
        const OnTimeout& onTimeout);
     
-    /**
-     * Return the next unique pending interest ID.
-     */
-    static uint64_t 
-    getNextPendingInterestId()
-    {
-      return ++lastPendingInterestId_;
-    }
-    
-    /**
-     * Return the pendingInterestId given to the constructor.
-     */
-    uint64_t 
-    getPendingInterestId() { return pendingInterestId_; }
-    
     const ptr_lib::shared_ptr<const Interest>& 
     getInterest() { return interest_; }
     
@@ -206,9 +199,6 @@
     callTimeout();
     
   private:
-    static uint64_t lastPendingInterestId_; /**< A class variable used to get the next unique ID. */
-
-    uint64_t pendingInterestId_;            /**< A unique identifier for this entry so it can be deleted */
     ptr_lib::shared_ptr<const Interest> interest_;
     const OnData onData_;
     const OnTimeout onTimeout_;
@@ -216,58 +206,71 @@
     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 registeredPrefixId A unique ID for this entry, which you should get with getNextRegisteredPrefixId().
      * @param prefix A shared_ptr for the prefix.
      * @param onInterest A function object to call when a matching data packet is received.
      */
-    RegisteredPrefix(uint64_t registeredPrefixId, const ptr_lib::shared_ptr<const Name>& prefix, const OnInterest& onInterest)
-      : registeredPrefixId_(registeredPrefixId)
-      , prefix_(prefix)
+    RegisteredPrefix(const Name& prefix, const OnInterest& onInterest)
+      : prefix_(new Name(prefix))
       , onInterest_(onInterest)
     {
     }
     
-    /**
-     * Return the next unique entry ID.
-     */
-    static uint64_t 
-    getNextRegisteredPrefixId()
+    const Name& 
+    getPrefix() const
     {
-      return ++lastRegisteredPrefixId_;
-    }
-    
-    /**
-     * Return the registeredPrefixId given to the constructor.
-     */
-    uint64_t 
-    getRegisteredPrefixId()
-    {
-      return registeredPrefixId_;
-    }
-    
-    const ptr_lib::shared_ptr<const Name>& 
-    getPrefix()
-    {
-      return prefix_;
+      return *prefix_;
     }
     
     const OnInterest& 
-    getOnInterest()
+    getOnInterest() const
     {
       return onInterest_;
     }
     
   private:
-    static uint64_t lastRegisteredPrefixId_; /**< A class variable used to get the next unique ID. */
-
-    uint64_t registeredPrefixId_;            /**< A unique identifier for this entry so it can be deleted */
-    ptr_lib::shared_ptr<const Name> prefix_;
+    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;
@@ -300,7 +303,7 @@
    */  
   void 
   registerPrefixHelper
-    (uint64_t registeredPrefixId, const ptr_lib::shared_ptr<const Name>& prefix, const OnInterest& onInterest, 
+    (const ptr_lib::shared_ptr<RegisteredPrefix> &prefixToRegister, 
      const OnRegisterFailed& onRegisterFailed, const ForwardingFlags& flags);
 
   /**
@@ -309,9 +312,7 @@
    * This method actually sets entry in a local interest filter table
    */
   void
-  registerPrefixFinal(uint64_t registeredPrefixId,
-                      const ptr_lib::shared_ptr<const Name>& prefix,
-                      const OnInterest& onInterest,
+  registerPrefixFinal(const ptr_lib::shared_ptr<RegisteredPrefix> &prefixToRegister,
                       const OnRegisterFailed& onRegisterFailed,
                       const ptr_lib::shared_ptr<const Interest>&, const ptr_lib::shared_ptr<Data>&);
   
diff --git a/src/face.cpp b/src/face.cpp
index 1161192..45d577b 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -10,8 +10,8 @@
 using namespace std;
 
 namespace ndn {
-  
-uint64_t 
+
+const PendingInterestId*
 Face::expressInterest
   (const Name& name, const Interest *interestTemplate, const OnData& onData, const OnTimeout& onTimeout)
 {
diff --git a/src/node.cpp b/src/node.cpp
index d227199..22f4963 100644
--- a/src/node.cpp
+++ b/src/node.cpp
@@ -25,9 +25,6 @@
 
 namespace ndn {
 
-uint64_t Node::PendingInterest::lastPendingInterestId_ = 0;
-uint64_t Node::RegisteredPrefix::lastRegisteredPrefixId_ = 0;
-
 Node::Node(const ptr_lib::shared_ptr<Transport>& transport)
   : pitTimeoutCheckTimerActive_(false)
   , transport_(transport)
@@ -48,28 +45,35 @@
   processEventsTimeoutTimer_ = ptr_lib::make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
 }
 
-uint64_t 
+const PendingInterestId*
 Node::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
 {
   if (!transport_->isConnected())
     transport_->connect(*ioService_,
                         ptr_lib::bind(&Node::onReceiveElement, this, _1));
-  
-  uint64_t pendingInterestId = PendingInterest::getNextPendingInterestId();
-  pendingInterestTable_.push_back(ptr_lib::shared_ptr<PendingInterest>(new PendingInterest
-    (pendingInterestId, ptr_lib::shared_ptr<const Interest>(new Interest(interest)), onData, onTimeout)));
 
-  transport_->send(interest.wireEncode());
+  ptr_lib::shared_ptr<const Interest> interestToExpress(new Interest(interest));
+  
+  ioService_->post(func_lib::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)
+{
+  pendingInterestTable_.push_back(ptr_lib::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));
   }
-  
-  return pendingInterestId;
 }
-
+    
 void
 Node::put(const Data &data)
 {
@@ -82,83 +86,78 @@
 
 
 void
-Node::removePendingInterest(uint64_t pendingInterestId)
+Node::removePendingInterest(const PendingInterestId *pendingInterestId)
 {
-  // Go backwards through the list so we can erase entries.
-  // Remove all entries even though pendingInterestId should be unique.
-  for (int i = (int)pendingInterestTable_.size() - 1; i >= 0; --i) {
-    if (pendingInterestTable_[i]->getPendingInterestId() == pendingInterestId)
-      pendingInterestTable_.erase(pendingInterestTable_.begin() + i);
-  }
+  ioService_->post(func_lib::bind(&Node::asyncRemovePendingInterest, this, pendingInterestId));
 }
 
-uint64_t 
+
+void
+Node::asyncRemovePendingInterest(const PendingInterestId *pendingInterestId)
+{
+  std::remove_if(pendingInterestTable_.begin(), pendingInterestTable_.end(),
+                 MatchPendingInterestId(pendingInterestId));
+}
+
+const RegisteredPrefixId*
 Node::registerPrefix
   (const Name& prefix, const OnInterest& onInterest, const OnRegisterFailed& onRegisterFailed, const ForwardingFlags& flags)
 {
-  // Get the registeredPrefixId now so we can return it to the caller.
-  uint64_t registeredPrefixId = RegisteredPrefix::getNextRegisteredPrefixId();
-  ptr_lib::shared_ptr<const Name> prefixPtr = ptr_lib::make_shared<const Name>(prefix);
+  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,
-                                         registeredPrefixId, prefixPtr, onInterest, onRegisterFailed, flags),
-                          func_lib::bind(onRegisterFailed, prefixPtr));
+                                         prefixToRegister, onRegisterFailed, flags),
+                          func_lib::bind(onRegisterFailed, prefixToRegister->getPrefix().shared_from_this()));
 
     // @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(registeredPrefixId, prefixPtr, onInterest, onRegisterFailed, flags);
+    registerPrefixHelper(prefixToRegister, onRegisterFailed, flags);
   
-  return registeredPrefixId;
+  return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
 }
 
 void
-Node::removeRegisteredPrefix(uint64_t registeredPrefixId)
+Node::removeRegisteredPrefix(const RegisteredPrefixId *registeredPrefixId)
 {
-  // Go backwards through the list so we can erase entries.
-  // Remove all entries even though pendingInterestId should be unique.
-
-  for (RegisteredPrefixTable::iterator i = registeredPrefixTable_.begin();
-       i != registeredPrefixTable_.end();
-       ++i)
+  RegisteredPrefixTable::iterator i = std::find_if(registeredPrefixTable_.begin(), registeredPrefixTable_.end(),
+                                                   MatchRegisteredPrefixId(registeredPrefixId));  
+  if (i != registeredPrefixTable_.end())
     {
-      if ((*i)->getRegisteredPrefixId() == registeredPrefixId) {
-        ForwardingEntry forwardingEntry("unreg", *(*i)->getPrefix(), faceId_);
-        Data data;
-        data.setContent(forwardingEntry.wireEncode());
+      ForwardingEntry forwardingEntry("unreg", (*i)->getPrefix(), faceId_);
+      Data data;
+      data.setContent(forwardingEntry.wireEncode());
         
-        SignatureSha256WithRsa signature;
-        signature.setValue(Block(Tlv::SignatureValue, ptr_lib::make_shared<Buffer>()));
-        data.setSignature(signature);
+      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());
+      // 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 interest(interestName);
+      interest.setScope(1);
+      interest.setInterestLifetime(1000);
 
-        expressInterest(interest, OnData(), OnTimeout());
+      expressInterest(interest, OnData(), OnTimeout());
         
-        registeredPrefixTable_.erase(i);
-        break;
-      }
+      registeredPrefixTable_.erase(i);
     }
+
+  // there cannot be two registered prefixes with the same id. if there are, then something is broken
 }
 
 void 
-Node::registerPrefixHelper(uint64_t registeredPrefixId,
-                           const ptr_lib::shared_ptr<const Name>& prefix,
-                           const OnInterest& onInterest,
+Node::registerPrefixHelper(const ptr_lib::shared_ptr<RegisteredPrefix> &prefixToRegister,
                            const OnRegisterFailed& onRegisterFailed, 
                            const ForwardingFlags& flags)
 {
@@ -166,7 +165,7 @@
 
   // 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", *prefix, -1, flags, -1);
+  ForwardingEntry forwardingEntry("selfreg", prefixToRegister->getPrefix(), -1, flags, -1);
   Block content = forwardingEntry.wireEncode();
 
   // Set the ForwardingEntry as the content of a Data packet and sign.
@@ -192,14 +191,12 @@
 
   expressInterest(interest,
                   func_lib::bind(&Node::registerPrefixFinal, this,
-                                 registeredPrefixId, prefix, onInterest, onRegisterFailed, _1, _2),
-                  func_lib::bind(onRegisterFailed, prefix));
+                                 prefixToRegister, onRegisterFailed, _1, _2),
+                  func_lib::bind(onRegisterFailed, prefixToRegister->getPrefix().shared_from_this()));
 }
 
 void
-Node::registerPrefixFinal(uint64_t registeredPrefixId,
-                          const ptr_lib::shared_ptr<const Name>& prefix,
-                          const OnInterest& onInterest,
+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)
 {
@@ -208,7 +205,7 @@
 
   if (content.getAll().empty())
     {
-      onRegisterFailed(prefix);
+      onRegisterFailed(prefixToRegister->getPrefix().shared_from_this());
       return;
     }
 
@@ -222,7 +219,7 @@
         entry.wireDecode(*val);
 
         // Save the onInterest callback and send the registration interest.
-        registeredPrefixTable_.push_back(ptr_lib::make_shared<RegisteredPrefix>(registeredPrefixId, prefix, onInterest));
+        registeredPrefixTable_.push_back(prefixToRegister);
 
         /// @todo Notify user about successful registration
         
@@ -237,14 +234,14 @@
 
         // std::cerr << "StatusReponse: " << resp << std::endl;
       
-        onRegisterFailed(prefix);
+        onRegisterFailed(prefixToRegister->getPrefix().shared_from_this());
         return;
       }
     default:
       {
         // failed :(
       
-        onRegisterFailed(prefix);
+        onRegisterFailed(prefixToRegister->getPrefix().shared_from_this());
         return;
       }
     }
@@ -343,7 +340,7 @@
     
       RegisteredPrefixTable::iterator entry = getEntryForRegisteredPrefix(interest->getName());
       if (entry != registeredPrefixTable_.end()) {
-        (*entry)->getOnInterest()((*entry)->getPrefix(), interest, *transport_, (*entry)->getRegisteredPrefixId());
+        (*entry)->getOnInterest()((*entry)->getPrefix().shared_from_this(), interest);
       }
     }
   else if (block.type() == Tlv::Data)
@@ -406,7 +403,7 @@
        ++i)
     {
       if (longestPrefix == registeredPrefixTable_.end() ||
-          (*i)->getPrefix()->size() > (*longestPrefix)->getPrefix()->size())
+          (*i)->getPrefix().size() > (*longestPrefix)->getPrefix().size())
         {
           longestPrefix = i;
         }
@@ -414,11 +411,9 @@
   return longestPrefix;
 }
 
-Node::PendingInterest::PendingInterest(uint64_t pendingInterestId,
-                                       const ptr_lib::shared_ptr<const Interest>& interest,
+Node::PendingInterest::PendingInterest(const ptr_lib::shared_ptr<const Interest>& interest,
                                        const OnData& onData, const OnTimeout& onTimeout)
-: pendingInterestId_(pendingInterestId),
-  interest_(interest),
+: interest_(interest),
   onData_(onData), onTimeout_(onTimeout)
 {
   // Set up timeoutTime_.
diff --git a/tests/test-publish-async.cpp b/tests/test-publish-async.cpp
index 92fcae8..b6a680f 100644
--- a/tests/test-publish-async.cpp
+++ b/tests/test-publish-async.cpp
@@ -72,8 +72,7 @@
   
   // onInterest.
   void operator()
-     (const ptr_lib::shared_ptr<const Name>& prefix, const ptr_lib::shared_ptr<const Interest>& interest, Transport& transport,
-      uint64_t registeredPrefixId) 
+     (const ptr_lib::shared_ptr<const Name>& prefix, const ptr_lib::shared_ptr<const Interest>& interest) 
   {
     ++responseCount_;
     
@@ -90,7 +89,7 @@
 
     // Unregister prefix to ensure that the processing thread finishes after Data
     // packet is send out to the forwarder
-    face_.unsetInterestFilter(registeredPrefixId);
+    face_.unsetInterestFilter(id_);
   }
   
   // onRegisterFailed.
@@ -103,6 +102,8 @@
   KeyChainImpl<SecPublicInfoMemory, SecTpmMemory> &keyChain_;
   Face &face_;
   int responseCount_;
+
+  const RegisteredPrefixId *id_;
 };
 
 int main(int argc, char** argv)
@@ -128,7 +129,7 @@
     Echo echo(keyChain, face);
     Name prefix("/testecho");
     cout << "Register prefix  " << prefix.toUri() << endl;
-    face.setInterestFilter(prefix, func_lib::ref(echo), func_lib::ref(echo));
+    echo.id_ = face.setInterestFilter(prefix, func_lib::ref(echo), func_lib::ref(echo));
     
     face.processEvents();
   } catch (std::exception& e) {