Correcting bugs with cleaning timeouts in PIT/RIT/ContentStore

Removing RIT concept. Instead, keep track of nonces for each PIT entry.

Many changes in CcnxL3Protocol regarding Interest/Data handling (NACK
are not yet handled at all)

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!! Remove when is not actual !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Code is not compiling !!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/model/ccnx-l3-protocol.cc b/model/ccnx-l3-protocol.cc
index 63c9049..a479390 100644
--- a/model/ccnx-l3-protocol.cc
+++ b/model/ccnx-l3-protocol.cc
@@ -41,6 +41,10 @@
 #include "ccnx-net-device-face.h"
 
 #include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+
+using namespace boost::tuples;
+using namespace boost::lambda;
 
 NS_LOG_COMPONENT_DEFINE ("CcnxL3Protocol");
 
@@ -257,8 +261,11 @@
             // Deserialization. Exception may be thrown
             packet->RemoveHeader (*header);
             NS_ASSERT_MSG (packet->GetSize () == 0, "Payload of Interests should be zero");
-            
-            OnInterest (face, header, p/*original packet*/);  
+
+            if (header->GetNack () > 0)
+              OnNack (face, header, p/*original packet*/);
+            else
+              OnInterest (face, header, p/*original packet*/);  
             break;
           }
         case CcnxHeaderHelper::CONTENT_OBJECT:
@@ -284,376 +291,199 @@
     }
 }
 
+void
+CcnxL3Protocol::OnNack (const Ptr<CcnxFace> &face,
+                        Ptr<CcnxInterestHeader> &header,
+                        const Ptr<const Packet> &p)
+{
+  NS_LOG_FUNCTION (face << header << p);
+
+  // Huh... Ignore all this for now
+  
+  /*if( header->IsCongested () == false )
+    m_pit->LeakBucket(incomingFace,1);
+        
+        
+    m_droppedInterestsTrace (header, DROP_CONGESTION,
+    m_node->GetObject<Ccnx> (), incomingFace);
+        
+    m_pit->modify(pitEntry, CcnxPitEntry::DeleteOutgoing(incomingFace));*/
+
+  // No matter is it duplicate or not, if it is a NACK message, remove all possible incoming
+  // entries for this interface (NACK means that neighbor gave up trying and there is no
+  // point of sending data in this direction)
+  
+  // NS_LOG_INFO("Before (header->IsNack()) && (pitEntry != m_pit->end ())");
+  // if ((header->IsNack()) && (pitEntry != m_pit->end ()))
+  //   {
+  //     //m_pit->erase (pitEntry);
+  //     NS_LOG_INFO("TRUE");
+  //     m_pit->modify(pitEntry, CcnxPitEntry::DeleteIncoming(incomingFace));
+  //   }
+
+  //   m_fib->modify (m_fib->iterator_to (pitEntry->m_fibEntry),
+  // CcnxFibEntry::UpdateStatus(incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
+
+  // if (!pitEntry.AreThereMoreFacesToTry ())
+  //   {
+  //     BOOST_FOREACH (const CcnxPitEntryIncomingFace face, pitEntry.m_incoming)
+  //       {
+  //         // check all entries if the name of RIT entry matches the name of interest
+  //         for (CcnxRitByNonce::type::iterator it = m_rit->begin(); it != m_rit->end(); it++)
+  //           {
+  //             if (it->m_prefix == iter->GetPrefix() )
+  //               {
+  //                 header->SetNonce(it->m_nonce);
+  //                 header->SetNack(true);
+  //                 SendInterest(face.m_face, header, packet->Copy());
+  //               }
+  //           }
+  //       }
+
+  //     m_pit->erase(pitEntry);
+
+  //     return;
+  //   }
+}
+
 // Processing Interests
+//
+// !!! Key point.
+// !!! All interests should be answerred!!! Either later with data, immediately with data, or immediately with NACK
 void CcnxL3Protocol::OnInterest (const Ptr<CcnxFace> &incomingFace,
                                  Ptr<CcnxInterestHeader> &header,
                                  const Ptr<const Packet> &packet)
 {
-  NS_LOG_LOGIC ("Receiving interest from " << &incomingFace);
-  m_receivedInterestsTrace (header, m_node->GetObject<Ccnx> (), incomingFace);
+  NS_LOG_FUNCTION (incomingFace << header << packet);
+  // m_receivedInterestsTrace (header, m_node->GetObject<Ccnx> (), incomingFace);
 
-    
-    if( header->IsNack () )
-    {
-        NS_LOG_INFO("============");
-        NS_LOG_INFO("NACK");
-        NS_LOG_INFO("==========");
-        /*if( header->IsCongested () == false )
-            m_pit->LeakBucket(incomingFace,1);
-        
-        
-        m_droppedInterestsTrace (header, DROP_CONGESTION,
-                                 m_node->GetObject<Ccnx> (), incomingFace);
-        
-        m_pit->modify(pitEntry, CcnxPitEntry::DeleteOutgoing(incomingFace));*/
-    }
+  // Lookup of Pit (and associated Fib) entry for this Interest 
+  const CcnxPitEntry &pitEntry;
+  bool isNew;
+  bool isDuplicated;
+  tie (pitEntry, isNew, isDuplicated) = m_pit->Lookup (*header);
 
-    
-    
-    
-  // Lookup of Pit and Fib entries for this Interest 
-  CcnxFibEntryContainer::type::iterator fibEntry;
-  CcnxPitEntryContainer::type::iterator pitEntry = m_pit->Lookup (*header, fibEntry);  
-    
-  // No matter is it duplicate or not, if it is a NACK message, remove all possible incoming
-  // entries for this interface (NACK means that neighbor gave up trying and there is no
-  // point of sending data in this direction)
-    NS_LOG_INFO("Before (header->IsNack()) && (pitEntry != m_pit->end ())");
-  if ((header->IsNack()) && (pitEntry != m_pit->end ()))
+  if (isDuplicated) 
     {
-      //m_pit->erase (pitEntry);
-        NS_LOG_INFO("TRUE");
-        m_pit->modify(pitEntry, CcnxPitEntry::DeleteIncoming(incomingFace));
-    }
-    
-    NS_LOG_INFO("Before WasRecentlySatisfied");
-    /*if (m_rit->WasRecentlySatisfied (*header))
-    {
-        return;
-    }*/
-  if (m_rit->WasRecentlySatisfied (*header))
-    {
-        NS_LOG_INFO("------------");
-        NS_LOG_INFO("Entering WasRecentlySatisfied");
-        NS_LOG_INFO("------------");
-      // duplicate interests (same nonce) from applications are just ignored
-      if (incomingFace->IsLocal() == true) 
-          return;
-        
-      // Update metric status for the incoming interface in the corresponding FIB entry
-      /*if (fibEntry != m_fib->end())
-        m_fib->modify (m_fib->iterator_to (pitEntry->m_fibEntry),
-                       CcnxFibEntry::UpdateStatus(incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
+      /**
+       * This condition will handle "routing" loops and also recently satisfied interests.
+       * Every time interest is satisfied, PIT entry (with empty incoming and outgoing faces)
+       * is kept for another small chunk of time.
+       */
       
-      //Trace duplicate interest  
-      m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
-                               m_node->GetObject<Ccnx> (), incomingFace);
-        
-      bool isMine = false;
-      //TypeId tid = TypeId ("ns3::CcnxProducer");
-      for(uint32_t i=0; i<m_node->GetNApplications();i++)
-        {
-            Ptr<Application> app = m_node->GetApplication(i);
-            NS_LOG_INFO("ApplicationName = " << app->GetTypeId().GetName());
-            if(app->GetTypeId().GetName() == "ns3::CcnxProducer")
-              {
-                if((DynamicCast<CcnxProducer>(app))->GetPrefix () == header->GetName ())
-                {
-                    isMine = true;
-                    break;
-                }
-              }
-        }
-    
-      Ptr<Packet> contentObject = m_contentStore->Lookup (header);
-      if ((isMine == true) || (contentObject != NULL))
-        {
-            //never respond with NACK to NACK
-            if(header->IsNack () )
-                return;
-            
-            // always return a duplicate packet
-            header->SetNack(true);
-            //Trace duplicate interest  
-            m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
-                                     m_node->GetObject<Ccnx> (), incomingFace);
+      // //Trace duplicate interest  
+      // m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST, m_node->GetObject<Ccnx> (), incomingFace);
 
-            SendInterest(incomingFace, header, packet->Copy());
-			
-			return;
-        }  
-           
-        
-      // check PIT.  or there is no outgoing entry for this interface,
-      // silently drop the duplicate packet
-        
-      // If no entry found, silently drop
-      if( pitEntry == m_pit->end() ) 
-        return;
-        
-      // If PIT entry timed out, silently drop
-      if( pitEntry->m_timerExpired == true ) 
-        return;
-        
-      // loop?
-        
-      // Check if there is no outgoing entry for the interface or different nonce
-      // (i.e., got a duplicate packet, but we haven't sent interest to this
-      // interface)
-      //
-      // This case means that there is a loop in the network.
-      // So, prune this link, but do not remove PIT entry
-        
-      // Alex, check this condition!!
-      if(pitEntry->m_outgoing.size () == 0)
-        {
-            //never respond with NACK to NACK
-            if(header->IsNack () )
-                return;
-            
-            // always return a duplicate packet
-            header->SetNack(true);
-            //Trace duplicate interest  
-            m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
-                                     m_node->GetObject<Ccnx> (), incomingFace);
+      header->SetNack (CcnxInterestHeader::NACK_LOOP);
+      Ptr<Packet> packet = Create<Packet> ();
+      packet->AddHeader (*header);
 
-            SendInterest(incomingFace, header, packet->Copy());
-            return;
-        }
+      SendInterest (m_incomingFace, header, packet);
       
-        
-        // At this point:
-		// - there is a non-expired PIT entry,
-		// - there is an outgoing interest to the interface, and
-		// - a nonce in outgoing entry is equal to a nonce in the received duplicate packet
-        
-		// Should perform:
-		// Cleaning outgoing entry
-		// If there are no outgoing interests and available interfaces left (pe->availableInterfaces),
-		// prune all incoming interests, otherwise allow forwarding of the interest
-		if( header->IsNack () )
-		{
-			if( header->IsCongested () == false )
-                m_pit->LeakBucket(incomingFace,1);
-            
-            m_pit->modify(pitEntry, CcnxPitEntry::DeleteOutgoing(incomingFace));
-        }
-		else
-		{
-			//poit->waitingInVain = true;
-		}
-
-        
-        // prune all incoming interests
-        if((pitEntry->m_outgoing.size() ==0) && (pitEntry->m_fibEntry.m_faces.size() == 0))
-        {
-            BOOST_FOREACH (const CcnxPitEntryIncomingFace face, pitEntry->m_incoming)
-            {
-                if(face.m_face->IsLocal() == false)
-                {
-                  // check all entries if the name of RIT entry matches the name of interest
-                  for (CcnxRitByNonce::type::iterator it = m_rit->begin(); it != m_rit->end(); it++)
-                  {
-                    if (it->m_prefix == pitEntry->GetPrefix() )
-                      {
-                        
-                        header->SetNonce(it->m_nonce);
-                        header->SetNack(true);
-                        SendInterest(face.m_face, header, packet->Copy());
-                        break;
-                      }
-                  }
-                }
-             }
-            
-            // Finally, remote the PIT entry
-            m_pit->erase (pitEntry);
-            
-            return; // stop processing
-        }
-        
-      if(pitEntry->m_fibEntry.m_faces.size() == 0)  
-        return;*/
-        return;
-    }
-    
-    
-    
-  // Otherwise,
-  // propagate the interest
-  //
-  // method `propagateInterest' can/should try different interface
-  // from `availableInterfaces' list
-    
-  NS_LOG_INFO("Before SetRecentlySatisfied");
-  m_rit->SetRecentlySatisfied (*header); 
-
-  NS_LOG_INFO("Cache Lookup for " << header->GetName());
-  Ptr<Packet> contentObject = m_contentStore->Lookup (header);
-  if (contentObject != NULL)
-    {
-      NS_LOG_INFO("Found in cache");
-        
-      TransmittedDataTrace (contentObject, CACHED,
-                            m_node->GetObject<Ccnx> (), incomingFace);
-      incomingFace->Send (contentObject);
+      // //Trace duplicate interest  
+      // m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST, m_node->GetObject<Ccnx> (), incomingFace);
       return;
     }
+
+  Ptr<Packet> contentObject;
+  Ptr<CcnxContentObjectHeader> contentObjectHeader;
+  tie (contentObject, contentObjectHeader) = m_contentStore->Lookup (header);
+  if (contentObject != 0)
+    {
+      NS_ASSERT_MSG (pitEntry.m_incoming.size () == 0,
+                     "Something strange. Data is cached, but size of incoming interests is not zero...");
+      NS_ASSERT (contentObjectHeader != 0);
+      
+      NS_LOG_LOGIC("Found in cache");
+        
+      // TransmittedDataTrace (contentObject, CACHED,
+      //                       m_node->GetObject<Ccnx> (), incomingFace);
+      SendContentObject (incomingFace, contentObjectHeader, contentObject);
+
+      // Set pruning timout on PIT entry (instead of deleting the record)
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     boost::bind (&CcnxPitEntry::SetExpireTime, _1,
+                                  Simulator::Now () + m_pit->GetPitEntryPruningTimeout ()));
+      return;
+    }
+
+  // \todo Detect retransmissions. Not yet sure how...
   
   // Data is not in cache
-  NS_LOG_INFO("Before inFace and OutFace");
-  CcnxPitEntryIncomingFaceContainer::type::iterator inFace = pitEntry->m_incoming.find (incomingFace);
-  CcnxPitEntryOutgoingFaceContainer::type::iterator outFace = pitEntry->m_outgoing.find (incomingFace);
-    
-  NS_LOG_INFO("Before (pitEntry != m_pit->end()) && (pitEntry->m_timerExpired == false)");
-  if ((pitEntry != m_pit->end()) && (pitEntry->m_timerExpired == false))
+  CcnxPitEntryIncomingFaceContainer::type::iterator inFace = pitEntry.m_incoming.find (incomingFace);
+  CcnxPitEntryOutgoingFaceContainer::type::iterator outFace = pitEntry.m_outgoing.find (incomingFace);
+
+  if (inFace != pitEntry.m_incoming.end ())
     {
-        NS_LOG_INFO("Entering (pitEntry != m_pit->end()) && (pitEntry->m_timerExpired == false)");
-        
-        if(inFace->m_face == 0)
-            NS_LOG_INFO("in face is null");
-        if(outFace->m_face == 0)
-            NS_LOG_INFO("outface is null");
-        if(outFace == pitEntry->m_outgoing.end())
-            NS_LOG_INFO("OUTFACE = END");
-        
-        // If we're expecting data from the interface we got the interest from ("producer" asks us for "his own" data)
-        // Give up this interface, but keep a small hope when the returned packet doesn't have PRUNE status
-        if(outFace != pitEntry->m_outgoing.end()) // this is correct
-        {
-            NS_LOG_INFO("Entering outFace != pitEntry->m_outgoing.end()");
-            if( header->IsCongested() == true )
-            {
-                NS_LOG_INFO("Entering header->IsCongested() == true");
-                m_pit->LeakBucket(incomingFace, 1);
-                m_pit->modify (pitEntry, CcnxPitEntry::DeleteOutgoing(outFace->m_face));
-            }
-            //else
-            //    poit->waitingInVain = true;
-            
-            // Update metric status for the incoming interface in the corresponding FIB entry
-            if(fibEntry != m_fib->end())
-                m_fib->modify(m_fib->iterator_to (pitEntry->m_fibEntry),
-                              CcnxFibEntry::UpdateStatus(incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
-        }
-    }
-
-  NS_LOG_INFO("Before (pitEntry->m_outgoing.size() == 0) && (pitEntry->m_fibEntry.m_faces.size() == 0)");
-  if((pitEntry->m_outgoing.size() == 0) && (pitEntry->m_fibEntry.m_faces.size() == 0))
-      // prune all incoming interests
-    {
-        
-        for(CcnxPitEntryContainer::type::iterator iter = m_pit->begin();
-            iter != m_pit->end(); 
-            iter++)
-        {
-            /*for(CcnxPitEntryIncomingFaceContainer::type::iterator face = iter->m_incoming.begin();
-                face != iter->m_incoming.end();
-                face++)*/
-            BOOST_FOREACH (const CcnxPitEntryIncomingFace face, iter->m_incoming)
-            {
-              if(face.m_face->IsLocal() == true)
-                {
-                    //returnInterestToApp( pkt, -piit->interfaceIndex );
-                    //continue;
-                }
-                
-                // check all entries if the name of RIT entry matches the name of interest
-                for (CcnxRitByNonce::type::iterator it = m_rit->begin(); it != m_rit->end(); it++)
-              {
-                if (it->m_prefix == iter->GetPrefix() )
-                  {
-                    header->SetNonce(it->m_nonce);
-                    header->SetNack(true);
-                    SendInterest(face.m_face, header, packet->Copy());
-                  }
-              }
-            }
-
-        }
-            
-        m_pit->erase(pitEntry);
-        
-        return; // there is nothing else to do
-    }
-
-    // Suppress this interest only if we're still expecting data from some other interface
-    if( pitEntry->m_outgoing.size() > 0 ) 
-    {
-        return; //ok. Now we can suppress this interest
-    }
-    
-    
-    // Prune and delete PIT entry if there are no available interfaces to propagate interest
-    if( pitEntry->m_fibEntry.m_faces.size() == 0)
-    {
-        //if no match is found in the FIB, drop packet
-        //printf( "Node %d: cannot process Interest packet %s (no interfaces left)\n", _node->nodeId, pkt->contentName );
-		
-        if(incomingFace->IsLocal() == false)
-        {
-            header->SetNack(true);
-            m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST,
-                                     m_node->GetObject<Ccnx> (), incomingFace);
-            SendInterest(incomingFace, header, packet->Copy());
-        }
-        
-        m_pit->erase(pitEntry);
-        
-    }
-
-    
-    
-    // otherwise, try one of the available interfaces
-    
-  // suppress interest if 
-  /*if (pitEntry->m_incoming.size () != 0 && // not a new PIT entry and
-      inFace != pitEntry->m_incoming.end ()) // existing entry, but interest received via different face
-    {
-      m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST,
-                                m_node->GetObject<Ccnx> (), incomingFace);
-      return;
-    }*/
-    
-    
-    //just in case of bug
-    header->SetNack(false);
-    header->SetCongested(false);
-  
-    NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
-
-    m_pit->modify (pitEntry, CcnxPitEntry::AddIncoming(incomingFace));
-    
-    bool propagated = m_forwardingStrategy->
-                      PropagateInterest (pitEntry, fibEntry,incomingFace, header, packet,
-                                         MakeCallback (&CcnxL3Protocol::SendInterest, this)
-                                        );
-
-    // If interest wasn't propagated further (probably, a limit is reached),
-    // prune and delete PIT entry if there are no outstanding interests.
-    // Stop processing otherwise.
-    if( (!propagated) && (pitEntry->m_outgoing.size() == 0)) // this line works
-      {
-        BOOST_FOREACH (const CcnxPitEntryIncomingFace face, pitEntry->m_incoming)
-          {
-            header->SetNack(true);
-            header->SetCongested(true);
-            NS_LOG_INFO("Sending CONGESTION packet");
-            SendInterest (face.m_face, header, packet->Copy());
-                
-            m_droppedInterestsTrace (header, DROP_CONGESTION,
-                                         m_node->GetObject<Ccnx> (), incomingFace);
-          }
+      // CcnxPitEntryIncomingFace.m_arrivalTime keeps track arrival time of the first packet... why?
       
-          m_pit->erase (pitEntry);
-      }
-    /*}
+      // this is almost definitely a retransmission. But should we trust the user on that?
+    }
   else
     {
-      m_droppedInterestsTrace (header, NDN_PIT_TIMER_EXPIRED,
-                                 m_node->GetObject<Ccnx> (), incomingFace);
-      return;
-    }*/
+      m_pit->modify (m_pit->iterator_to (m_pitpitEntry),
+                    iface = _1->m_incoming.insert (CcnxPitEntryIncoming (incomingFace, Simulator::Now ())));
+    }
+
+  if (outFace != pitEntry.m_outgoing.end ())
+    {
+      // got a non-duplicate interest from the face we have sent interest to
+      // Probably, there is no point in waiting data from that face... Not sure yet
+
+      // If we're expecting data from the interface we got the interest from ("producer" asks us for "his own" data)
+      // Mark interface YELLOW, but keep a small hope that data will come eventually.
+
+      // ?? not sure if we need to do that ?? ...
+      
+      m_fib->modify(m_fib->iterator_to (pitEntry.m_fibEntry),
+                    boost::bind (&CcnxFibEntry::UpdateStatus,
+                                 _1, incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
+
+      // suppress?
+    }
+  else if (pitEntry->m_outgoing.size() > 0) // Suppress this interest if we're still expecting data from some other face
+
+    {
+      // We are already expecting data later in future. Suppress the interest
+      // m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST, m_node->GetObject<Ccnx> (), incomingFace);
+      return; 
+    }
+
+  /////////////////////////////////////////////////////////////////////
+  // Propagate
+  /////////////////////////////////////////////////////////////////////
+  
+  NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
+  
+  bool propagated = m_forwardingStrategy->
+    PropagateInterest (pitEntry, fibEntry,incomingFace, header, packet,
+                       MakeCallback (&CcnxL3Protocol::SendInterest, this)
+                       );
+
+  // ForwardingStrategy will try its best to forward packet to at least one interface.
+  // If no interests was propagated, then there is not other option for forwarding or
+  // ForwardingStrategy failed to find it. 
+  if (!propagated)
+    {
+      Ptr<Packet> packet = Create<Packet> ();
+      header->SetNack (CcnxInterestHeader::NACK_CONGESTION);
+      packet.AddHeader (*header);
+
+      while (pitEntry.m_incoming.size () > 0)
+        {
+          SendInterest (pitEntry.m_incoming.front ().m_face, header, packet->Copy ());
+
+          pitEntry.m_incoming.pop_front ();
+
+          // m_droppedInterestsTrace (header, DROP_CONGESTION,
+          //                          m_node->GetObject<Ccnx> (), incomingFace);
+        }
+
+      // Set pruning timout on PIT entry (instead of deleting the record)
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     boost::bind (&CcnxPitEntry::SetExpireTime, _1,
+                                  Simulator::Now () + m_pit->GetPitEntryPruningTimeout ()));
+    }
 }
 
 // Processing ContentObjects
@@ -663,8 +493,8 @@
                              const Ptr<const Packet> &packet)
 {
     
-  NS_LOG_LOGIC ("Receiving contentObject from " << &incomingFace);
-  m_receivedDataTrace (header, payload, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+  NS_LOG_FUNCTION (incomingFace << header, payload, packet);
+  // m_receivedDataTrace (header, payload, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
 
   // 1. Lookup PIT entry
   try
@@ -675,46 +505,48 @@
   
       // Update metric status for the incoming interface in the corresponding FIB entry
       m_fib->modify (m_fib->iterator_to (pitEntry.m_fibEntry),
-                     CcnxFibEntry::UpdateStatus (incomingFace, CcnxFibFaceMetric::NDN_FIB_GREEN));
+                     boost::bind (CcnxFibEntry::UpdateStatus, _1, incomingFace, CcnxFibFaceMetric::NDN_FIB_GREEN));
   
       // Add or update entry in the content store
-      NS_LOG_INFO("Cached " << header->GetName());
       m_contentStore->Add (header, payload);
 
-      CcnxPitEntryOutgoingFaceContainer::type::iterator
-        out = pitEntry.m_outgoing.find (incomingFace);
+      CcnxPitEntryOutgoingFaceContainer::type::iterator out = pitEntry.m_outgoing.find (incomingFace);
   
       // If we have sent interest for this data via this face, then update stats.
       if (out != pitEntry.m_outgoing.end ())
         {
-          m_pit->modify (m_pit->iterator_to (pitEntry),
-                         CcnxPitEntry::EstimateRttAndRemoveFace(out, m_fib));
-          // face will be removed in the above call
+          m_fib->modify (m_fib->iterator_to (pitEntry.m_fibEntry),
+                         boost::bind (&CcnxFibEntry::UpdateRtt,
+                                      _1,
+                                      Simulator::Now () - out->m_sendTime));
         }
       else
         {
-          NS_LOG_WARN ("Node "<< m_node->GetId() <<
-                          ". PIT entry for "<< header->GetName ()<<" is valid, "
-                          "but outgoing entry for interface "<< incomingFace <<" doesn't exist\n");
+          // Unsolicited data, but we're interested in it... should we get it?
+          // Potential hole for attacks
+          
+          NS_LOG_ERROR ("Node "<< m_node->GetId() <<
+                       ". PIT entry for "<< header->GetName ()<<" is valid, "
+                       "but outgoing entry for interface "<< incomingFace <<" doesn't exist\n");
+
+          NS_ASSERT (false); // temporary put false here
         }
 
       //satisfy all pending incoming Interests
-      BOOST_FOREACH (const CcnxPitEntryIncomingFace &interest, pitEntry.m_incoming)
+      while (pitEntry.m_incoming.size () > 0)
         {
-          if (interest.m_face == incomingFace) continue; 
+          if (pitEntry.m_incoming.front ().m_face != incomingFace)
+            SendInterest (pitEntry.m_incoming.front ().m_face, header, packet->Copy ());
 
-          // may not work either because of 'const' thing
-          interest.m_face->Send (packet->Copy ()); // unfortunately, we have to copy packet... 
-          m_transmittedDataTrace (header, payload, FORWARDED, m_node->GetObject<Ccnx> (), interest.m_face);
+          pitEntry.m_incoming.pop_front ();
+
+          // m_transmittedDataTrace (header, payload, FORWARDED, m_node->GetObject<Ccnx> (), interest.m_face);
         }
 
-      m_pit->modify (m_pit->iterator_to (pitEntry), CcnxPitEntry::ClearIncoming()); // satisfy all incoming interests
-
-      if( pitEntry.m_outgoing.size()==0 ) // remove PIT when all outgoing interests are "satisfied"
-        {
-          m_pit->erase (m_pit->iterator_to (pitEntry));
-        }
-
+      // Set pruning timout on PIT entry (instead of deleting the record)
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     boost::bind (&CcnxPitEntry::SetExpireTime, _1,
+                                  Simulator::Now () + m_pit->GetPitEntryPruningTimeout ()));
     }
   catch (CcnxPitEntryNotFound)
     {
@@ -722,7 +554,7 @@
       //    (unsolicited data packets should not "poison" content store)
       
       //drop dulicated or not requested data packet
-      m_droppedDataTrace (header, payload, NDN_UNSOLICITED_DATA, m_node->GetObject<Ccnx> (), incomingFace);
+      // m_droppedDataTrace (header, payload, NDN_UNSOLICITED_DATA, m_node->GetObject<Ccnx> (), incomingFace);
       return; // do not process unsoliced data packets
     }
 }
@@ -738,13 +570,13 @@
   if (face->IsUp ())
     {
       NS_LOG_LOGIC ("Sending via face " << &face); //
-      m_transmittedInterestsTrace (header, m_node->GetObject<Ccnx> (), face);
+      // m_transmittedInterestsTrace (header, m_node->GetObject<Ccnx> (), face);
       face->Send (packet);
     }
   else
     {
       NS_LOG_LOGIC ("Dropping -- outgoing interface is down: " << &face);
-      m_droppedInterestsTrace (header, INTERFACE_DOWN, m_node->GetObject<Ccnx> (), face);
+      // m_droppedInterestsTrace (header, INTERFACE_DOWN, m_node->GetObject<Ccnx> (), face);
     }
 }
 
@@ -756,8 +588,6 @@
   NS_LOG_FUNCTION (this << "packet: " << &packet << ", face: "<< &face);
   NS_ASSERT_MSG (face != 0, "Face should never be NULL");
 
-  NS_ASSERT_MSG (false, "Should not be called for now");
-  
   if (face->IsUp ())
     {
       NS_LOG_LOGIC ("Sending via face " << &face); //
@@ -777,11 +607,12 @@
     return m_pit;
 }
 
-void
-CcnxL3Protocol::ScheduleLeakage()
-{
-    m_pit->LeakBuckets();
-    Time interval = MilliSeconds (NDN_INTEREST_RESET_PERIOD);
-    Simulator::Schedule (interval, &CcnxL3Protocol::ScheduleLeakage, this);
-}
+// void
+// CcnxL3Protocol::ScheduleLeakage()
+// {
+//     m_pit->LeakBuckets();
+//     Time interval = MilliSeconds (NDN_INTEREST_RESET_PERIOD);
+    
+//     Simulator::Schedule (interval, &CcnxL3Protocol::ScheduleLeakage, this);
+// }
 } //namespace ns3