Several fixes in forwarding strategies and NACK processing

- All strategies will forward to one green face first, if it exists
- Implemented logic to detect retransmitted interests (same face)
- If interest is retransmitted and all faces are exhausted during the
  propagation face, increase max retx counter and try again
- PIT entry lifetime is updated on every non-duplicate interest reception
diff --git a/model/ccnx-bestroute-strategy.cc b/model/ccnx-bestroute-strategy.cc
index ab525b5..b850d08 100644
--- a/model/ccnx-bestroute-strategy.cc
+++ b/model/ccnx-bestroute-strategy.cc
@@ -32,7 +32,9 @@
 
 namespace ns3 
 {
-    
+
+using namespace __ccnx_private;
+
 NS_OBJECT_ENSURE_REGISTERED (CcnxBestRouteStrategy);
   
 TypeId CcnxBestRouteStrategy::GetTypeId (void)
@@ -56,43 +58,51 @@
                                           const Ptr<const Packet> &packet)
 {
   NS_LOG_FUNCTION (this);
-  bool forwardedCount = 0;
 
-  try
+  // Try to work out with just green faces
+  bool greenOk = PropagateInterestViaGreen (pitEntry, incomingFace, header, packet);
+  if (greenOk)
+    return true;
+
+  int propagatedCount = 0;
+
+  BOOST_FOREACH (const CcnxFibFaceMetric &metricFace, pitEntry.m_fibEntry.m_faces.get<i_metric> ())
     {
-      for (uint32_t skip = 0; skip < pitEntry.m_fibEntry.m_faces.size (); skip++)
+      if (metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_RED) // all non-read faces are in front
+        break;
+      
+      if (metricFace.m_face == incomingFace) 
+        continue; // same face as incoming, don't forward
+
+      if (pitEntry.m_incoming.find (metricFace.m_face) != pitEntry.m_incoming.end ()) 
+        continue; // don't forward to face that we received interest from
+
+      CcnxPitEntryOutgoingFaceContainer::type::iterator outgoing =
+        pitEntry.m_outgoing.find (metricFace.m_face);
+      
+      if (outgoing != pitEntry.m_outgoing.end () &&
+          outgoing->m_retxCount >= pitEntry.m_maxRetxCount)
         {
-          const CcnxFibFaceMetric bestMetric = pitEntry.m_fibEntry.FindBestCandidate (skip);
-
-          if (bestMetric.m_status == CcnxFibFaceMetric::NDN_FIB_RED) // no point to send there
-            continue;
-
-          if (pitEntry.m_incoming.find (bestMetric.m_face) != pitEntry.m_incoming.end ()) 
-            continue; // don't forward to face that we received interest from
-
-          if (pitEntry.m_outgoing.find (bestMetric.m_face) != pitEntry.m_outgoing.end ()) // already forwarded before
-            continue;
-
-          bool faceAvailable = bestMetric.m_face->IsBelowLimit ();
-          if (!faceAvailable) // huh...
-            continue;
-
-          m_pit->modify (m_pit->iterator_to (pitEntry),
-                         ll::bind(&CcnxPitEntry::AddOutgoing, ll::_1, bestMetric.m_face));
-
-          // NS_LOG_DEBUG ("new outgoing entry for " << boost::cref (*metricFace.m_face));
-
-          bestMetric.m_face->Send (packet->Copy ());
-
-          forwardedCount++;
-          break; // if we succeeded in sending one packet, stop
+          continue; // already forwarded before during this retransmission cycle
         }
-    }
-  catch (CcnxFibEntry::NoFaces)
-    {
+
+      bool faceAvailable = metricFace.m_face->IsBelowLimit ();
+      if (!faceAvailable) // huh...
+        {
+          continue;
+        }
+
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind(&CcnxPitEntry::AddOutgoing, ll::_1, metricFace.m_face));
+
+      metricFace.m_face->Send (packet->Copy ());
+      
+      propagatedCount++;
+      break; // do only once
     }
 
-  return forwardedCount > 0;
+  NS_LOG_INFO ("Propagated to " << propagatedCount << " faces");
+  return propagatedCount > 0;
 }
     
 } //namespace ns3
diff --git a/model/ccnx-flooding-strategy.cc b/model/ccnx-flooding-strategy.cc
index 94c6512..f2add5f 100644
--- a/model/ccnx-flooding-strategy.cc
+++ b/model/ccnx-flooding-strategy.cc
@@ -34,7 +34,9 @@
 
 namespace ns3 
 {
-    
+
+using namespace __ccnx_private;
+
 NS_OBJECT_ENSURE_REGISTERED (CcnxFloodingStrategy);
     
 TypeId CcnxFloodingStrategy::GetTypeId (void)
@@ -58,9 +60,17 @@
                                          const Ptr<const Packet> &packet)
 {
   NS_LOG_FUNCTION (this);
-    
+
+  // Try to work out with just green faces
+  bool greenOk = PropagateInterestViaGreen (pitEntry, incomingFace, header, packet);
+  if (greenOk)
+    return true;
+
+  // boo... :(
+  
   int propagatedCount = 0;
-  BOOST_FOREACH (const CcnxFibFaceMetric &metricFace, pitEntry.m_fibEntry.m_faces)
+
+  BOOST_FOREACH (const CcnxFibFaceMetric &metricFace, pitEntry.m_fibEntry.m_faces.get<i_metric> ())
     {
       if (metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_RED) // all non-read faces are in front
         break;
@@ -70,14 +80,19 @@
 
       if (pitEntry.m_incoming.find (metricFace.m_face) != pitEntry.m_incoming.end ()) 
         continue; // don't forward to face that we received interest from
+
+      CcnxPitEntryOutgoingFaceContainer::type::iterator outgoing =
+        pitEntry.m_outgoing.find (metricFace.m_face);
       
-      if (pitEntry.m_outgoing.find (metricFace.m_face) != pitEntry.m_outgoing.end ()) 
-        continue; // already forwarded before
+      if (outgoing != pitEntry.m_outgoing.end () &&
+          outgoing->m_retxCount >= pitEntry.m_maxRetxCount)
+        {
+          continue; // already forwarded before during this retransmission cycle
+        }
 
       bool faceAvailable = metricFace.m_face->IsBelowLimit ();
       if (!faceAvailable) // huh...
         {
-          // NS_LOG_ERROR (boost::cref (*metricFace.m_face) << " limit !!!");
           continue;
         }
 
diff --git a/model/ccnx-forwarding-strategy.cc b/model/ccnx-forwarding-strategy.cc
index 40b9e47..869e424 100644
--- a/model/ccnx-forwarding-strategy.cc
+++ b/model/ccnx-forwarding-strategy.cc
@@ -21,8 +21,18 @@
 
 #include "ns3/assert.h"
 
-#include "ccnx-route.h"
 #include "ccnx-forwarding-strategy.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ccnx-interest-header.h"
+
+#include <boost/ref.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+namespace ll = boost::lambda;
+
+NS_LOG_COMPONENT_DEFINE ("CcnxForwardingStrategy");
 
 namespace ns3 {
 
@@ -50,11 +60,53 @@
 {
   m_pit = pit;
 }
-    
-// Ptr<CcnxPit>
-// CcnxForwardingStrategy::GetPit ()
-// {
-//   return m_pit;
-// }
-    
+
+bool
+CcnxForwardingStrategy::PropagateInterestViaGreen (const CcnxPitEntry  &pitEntry, 
+                                                   const Ptr<CcnxFace> &incomingFace,
+                                                   Ptr<CcnxInterestHeader> &header,
+                                                   const Ptr<const Packet> &packet)
+{
+  NS_LOG_FUNCTION (this);
+
+  int propagatedCount = 0;
+  
+  BOOST_FOREACH (const CcnxFibFaceMetric &metricFace, pitEntry.m_fibEntry.m_faces)
+    {
+      if (metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_RED ||
+          metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_YELLOW)
+        break; //propagate only to green faces
+
+      if (pitEntry.m_incoming.find (metricFace.m_face) != pitEntry.m_incoming.end ()) 
+        continue; // don't forward to face that we received interest from
+
+      CcnxPitEntryOutgoingFaceContainer::type::iterator outgoing =
+        pitEntry.m_outgoing.find (metricFace.m_face);
+      
+      if (outgoing != pitEntry.m_outgoing.end () &&
+          outgoing->m_retxCount >= pitEntry.m_maxRetxCount)
+        {
+          continue;
+        }
+      
+      bool faceAvailable = metricFace.m_face->IsBelowLimit ();
+      if (!faceAvailable) // huh...
+        {
+          // let's try different green face
+          continue;
+        }
+
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind(&CcnxPitEntry::AddOutgoing, ll::_1, metricFace.m_face));
+
+      metricFace.m_face->Send (packet->Copy ());
+      
+      propagatedCount++;
+      break; // propagate only one interest
+    }
+
+  return propagatedCount > 0;
+}
+
+
 } //namespace ns3
diff --git a/model/ccnx-forwarding-strategy.h b/model/ccnx-forwarding-strategy.h
index d7a5ab5..aff0909 100644
--- a/model/ccnx-forwarding-strategy.h
+++ b/model/ccnx-forwarding-strategy.h
@@ -51,7 +51,7 @@
   virtual ~CcnxForwardingStrategy ();
 
   /**
-   * @brief Interface method to propagate the insterest according to the forwarding strategy
+   * @brief Base method to propagate the insterest according to the forwarding strategy
    *
    * @param pitEntry      Reference to PIT entry (reference to corresponding FIB entry inside)
    * @param incomingFace  Incoming face
@@ -65,7 +65,7 @@
   PropagateInterest (const CcnxPitEntry  &pitEntry, 
                      const Ptr<CcnxFace> &incomingFace,
                      Ptr<CcnxInterestHeader> &header,
-                     const Ptr<const Packet> &packe) = 0;
+                     const Ptr<const Packet> &packet) = 0;
     
   /**
    * @brief Set link to PIT for the forwarding strategy
@@ -75,6 +75,25 @@
   void
   SetPit (Ptr<CcnxPit> pit);
 
+protected:
+  /**
+   * @brief Propage interest vie a green interface. Fail, if no green interfaces available
+   *
+   * @param pitEntry      Reference to PIT entry (reference to corresponding FIB entry inside)
+   * @param incomingFace  Incoming face
+   * @param header        CcnxInterestHeader
+   * @param packet        Original Interest packet
+   * @param sendCallback  Send callback
+   * @return true if interest was successfully propagated, false if all options have failed
+   *
+   * \see PropagateInterest
+   */
+  bool
+  PropagateInterestViaGreen (const CcnxPitEntry  &pitEntry, 
+                             const Ptr<CcnxFace> &incomingFace,
+                             Ptr<CcnxInterestHeader> &header,
+                             const Ptr<const Packet> &packet);
+  
 protected:  
   Ptr<CcnxPit> m_pit;
 };
diff --git a/model/ccnx-l3-protocol.cc b/model/ccnx-l3-protocol.cc
index 596b36a..7fb9aab 100644
--- a/model/ccnx-l3-protocol.cc
+++ b/model/ccnx-l3-protocol.cc
@@ -319,8 +319,10 @@
       return;
     }
 
-  NS_ASSERT_MSG (incomingFace == outFace->m_face, "Something is wrong");
-  incomingFace->LeakBucketByOnePacket ();
+  // This was done in error. Never, never do anything, except normal leakage. This way we ensure that we will not have losses,
+  // at least when there is only one client
+  //
+  // incomingFace->LeakBucketByOnePacket ();
 
   m_pit->modify (m_pit->iterator_to (pitEntry),
                  ll::bind (&CcnxPitEntry::SetWaitingInVain, ll::_1, outFace));
@@ -336,9 +338,9 @@
                      ll::bind (&CcnxPitEntry::RemoveIncoming, ll::_1, incomingFace));
     }
 
-  m_fib->modify(m_fib->iterator_to (pitEntry.m_fibEntry),
-                ll::bind (&CcnxFibEntry::UpdateStatus,
-                          ll::_1, incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
+  m_fib->modify (m_fib->iterator_to (pitEntry.m_fibEntry),
+                 ll::bind (&CcnxFibEntry::UpdateStatus,
+                           ll::_1, incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
 
   if (!pitEntry.AreAllOutgoingInVain ()) // not all ougtoing are in vain
     {
@@ -428,10 +430,13 @@
   CcnxPitEntryIncomingFaceContainer::type::iterator inFace = pitEntry.m_incoming.find (incomingFace);
   CcnxPitEntryOutgoingFaceContainer::type::iterator outFace = pitEntry.m_outgoing.find (incomingFace);
 
+  bool isRetransmitted = false;
+  
   if (inFace != pitEntry.m_incoming.end ())
     {
       // CcnxPitEntryIncomingFace.m_arrivalTime keeps track arrival time of the first packet... why?
-      
+
+      isRetransmitted = true;
       // this is almost definitely a retransmission. But should we trust the user on that?
     }
   else
@@ -440,6 +445,11 @@
                      ll::var(inFace) = ll::bind (&CcnxPitEntry::AddIncoming, ll::_1, incomingFace));
     }
 
+  // update PIT entry lifetime
+  m_pit->modify (m_pit->iterator_to (pitEntry),
+                 ll::bind (&CcnxPitEntry::UpdateLifetime, ll::_1,
+                           header->GetInterestLifetime ()));
+  
   if (outFace != pitEntry.m_outgoing.end ())
     {
       // got a non-duplicate interest from the face we have sent interest to
@@ -455,7 +465,8 @@
                               ll::_1, incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
     }
 
-  if (pitEntry.AreTherePromisingOutgoingFacesExcept (incomingFace))
+  if (!isRetransmitted &&
+      pitEntry.AreTherePromisingOutgoingFacesExcept (incomingFace))
     { // Suppress this interest if we're still expecting data from some other face
       
       // We are already expecting data later in future. Suppress the interest
@@ -472,6 +483,17 @@
   bool propagated = m_forwardingStrategy->
     PropagateInterest (pitEntry, incomingFace, header, packet);
 
+  if (isRetransmitted) //give another chance if retransmitted
+    {
+      // increase max number of allowed retransmissions
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind (&CcnxPitEntry::IncreaseAllowedRetxCount, ll::_1));
+
+      // try again
+      propagated = m_forwardingStrategy->
+        PropagateInterest (pitEntry, incomingFace, header, packet);
+    }
+  
   // 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. 
diff --git a/model/ccnx-pit-entry-outgoing-face.cc b/model/ccnx-pit-entry-outgoing-face.cc
index a0a8772..8527779 100644
--- a/model/ccnx-pit-entry-outgoing-face.cc
+++ b/model/ccnx-pit-entry-outgoing-face.cc
@@ -27,11 +27,17 @@
 CcnxPitEntryOutgoingFace::CcnxPitEntryOutgoingFace (Ptr<CcnxFace> face)
   : m_face (face)
   , m_sendTime (Simulator::Now ())
-  // , m_retxNum (0)
-  // , m_nonce (nonce)
-  // , m_outstanding (true)
+  , m_retxCount (0)
   , m_waitingInVain (false)
 {
 }
 
+void
+CcnxPitEntryOutgoingFace::UpdateOnRetransmit ()
+{
+  m_sendTime = Simulator::Now ();
+  m_retxCount++;
+  m_waitingInVain = false;
+}
+
 } // namespace ns3
diff --git a/model/ccnx-pit-entry-outgoing-face.h b/model/ccnx-pit-entry-outgoing-face.h
index 0fce545..c0fe80f 100644
--- a/model/ccnx-pit-entry-outgoing-face.h
+++ b/model/ccnx-pit-entry-outgoing-face.h
@@ -38,14 +38,18 @@
   Time m_sendTime;          ///< \brief time when the first outgoing interest is sent (for RTT measurements)
                             ///< \todo handle problem of retransmitted interests... Probably, we should include something similar
                             ///<       to TimeStamp TCP option for retransmitted (i.e., only lost interests will suffer)
-  // uint32_t m_retxNum;       ///< \brief number of retransmission
-  // int m_nonce;              ///< \brief nonce of the outgoing Interest
-  // bool m_outstanding;		///< \brief flag to indicate that this interest is currently pending
+  uint32_t m_retxCount;     ///< \brief number of retransmission
   bool m_waitingInVain;     ///< \brief when flag is set, we do not expect data for this interest, only a small hope that it will happen
 	
 public:
   CcnxPitEntryOutgoingFace (Ptr<CcnxFace> face);
 
+  /**
+   * @brief Update outgoing entry upon retransmission
+   */
+  void
+  UpdateOnRetransmit ();
+
   bool operator== (const CcnxPitEntryOutgoingFace &dst) { return *m_face==*dst.m_face; }
   bool operator== (Ptr<CcnxFace> face) { return *m_face==*face; }
 
diff --git a/model/ccnx-pit-entry.cc b/model/ccnx-pit-entry.cc
index 348f01b..5667c82 100644
--- a/model/ccnx-pit-entry.cc
+++ b/model/ccnx-pit-entry.cc
@@ -26,6 +26,7 @@
 #include "ns3/log.h"
 
 #include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
 namespace ll = boost::lambda;
 
 NS_LOG_COMPONENT_DEFINE ("CcnxPitEntry");
@@ -38,12 +39,21 @@
                             const CcnxFibEntry &fibEntry)
   : m_prefix (prefix)
   , m_fibEntry (fibEntry)
-  , m_expireTime (expireTime)
-  , m_timerExpired (false)
-  , m_counterExpirations (0)
+  , m_expireTime (Simulator::Now () + expireTime)
+  // , m_timerExpired (false)
+  // , m_counterExpirations (0)
+  , m_maxRetxCount (0)
 {
 }
 
+void
+CcnxPitEntry::UpdateLifetime (const Time &offsetTime)
+{
+  Time newExpireTime = Simulator::Now () + offsetTime;
+  if (newExpireTime > m_expireTime)
+    m_expireTime = newExpireTime;
+}
+
 CcnxPitEntryIncomingFaceContainer::type::iterator
 CcnxPitEntry::AddIncoming (Ptr<CcnxFace> face)
 {
@@ -68,7 +78,11 @@
   std::pair<CcnxPitEntryOutgoingFaceContainer::type::iterator,bool> ret =
     m_outgoing.insert (CcnxPitEntryOutgoingFace (face));
 
-  NS_ASSERT_MSG (ret.second, "Something is wrong");
+  if (!ret.second)
+    { // outgoing face already exists
+      m_outgoing.modify (ret.first,
+                         ll::bind (&CcnxPitEntryOutgoingFace::UpdateOnRetransmit, ll::_1));
+    }
 
   return ret.first;
 }
@@ -119,4 +133,10 @@
   return !inVain;
 }
 
+void
+CcnxPitEntry::IncreaseAllowedRetxCount ()
+{
+  m_maxRetxCount++;
+}
+
 }
diff --git a/model/ccnx-pit-entry.h b/model/ccnx-pit-entry.h
index 93e4869..162d7a5 100644
--- a/model/ccnx-pit-entry.h
+++ b/model/ccnx-pit-entry.h
@@ -45,7 +45,7 @@
 
 namespace __ccnx_private
 {
-// class i_face {};
+class i_retx {};
 }
 
 /**
@@ -85,7 +85,11 @@
       boost::multi_index::ordered_unique<
         boost::multi_index::tag<__ccnx_private::i_face>,
         boost::multi_index::member<CcnxPitEntryOutgoingFace, Ptr<CcnxFace>, &CcnxPitEntryOutgoingFace::m_face>
-      >
+      >,
+      boost::multi_index::ordered_non_unique<
+        boost::multi_index::tag<__ccnx_private::i_retx>,
+        boost::multi_index::member<CcnxPitEntryOutgoingFace, uint32_t, &CcnxPitEntryOutgoingFace::m_retxCount>
+      >    
     >
    > type;
 };
@@ -101,18 +105,25 @@
   /**
    * \brief PIT entry constructor
    * \param prefix Prefix of the PIT entry
+   * \param offsetTime Relative time to the current moment, representing PIT entry lifetime
    * \param fibEntry A FIB entry associated with the PIT entry
    */
-  CcnxPitEntry (Ptr<CcnxNameComponents> prefix, const Time &expireTime, const CcnxFibEntry &fibEntry);
+  CcnxPitEntry (Ptr<CcnxNameComponents> prefix, const Time &offsetTime, const CcnxFibEntry &fibEntry);
   
-  // // Get number of outgoing interests that we're expecting data from
-  // inline size_t numberOfPromisingInterests( ) const; 
-
+  /**
+   * @brief Update lifetime of PIT entry
+   *
+   * This function will update PIT entry lifetime to the maximum of the current lifetime and
+   * the lifetime Simulator::Now () + offsetTime
+   *
+   * @param offsetTime Relative time to the current moment, representing PIT entry lifetime
+   */
+  void
+  UpdateLifetime (const Time &offsetTime);
+  
   const CcnxNameComponents &
   GetPrefix () const
-  {
-    return *m_prefix;
-  }
+  { return *m_prefix; }
 
   /**
    * @brief Get current expiration time of the record
@@ -130,9 +141,7 @@
    */
   void
   SetExpireTime (const Time &expireTime)
-  {
-    m_expireTime = expireTime;
-  }
+  { m_expireTime = expireTime; }
   
   /**
    * @brief Check if nonce `nonce` for the same prefix has already been seen
@@ -212,6 +221,12 @@
    **/
   bool
   AreTherePromisingOutgoingFacesExcept (Ptr<CcnxFace> face) const;
+
+  /**
+   * @brief Increase maximum limit of allowed retransmission per outgoing face
+   */
+  void
+  IncreaseAllowedRetxCount ();
   
 protected:
   
@@ -227,8 +242,8 @@
   CcnxPitEntryOutgoingFaceContainer::type m_outgoing; ///< \brief container for outgoing interests
 
   Time m_expireTime;         ///< \brief Time when PIT entry will be removed
-  bool m_timerExpired;       ///< \brief flag indicating that PIT timer has expired
-  int  m_counterExpirations; ///< \brief whether timer is expired (+ number of times timer expired)
+
+  uint32_t m_maxRetxCount;   ///< @brief Maximum allowed number of retransmissions via outgoing faces
 };
 
 } // namespace ns3
diff --git a/model/ccnx-pit.cc b/model/ccnx-pit.cc
index 9770bd0..1cfa3f9 100644
--- a/model/ccnx-pit.cc
+++ b/model/ccnx-pit.cc
@@ -171,9 +171,8 @@
 
       entry = insert (end (),
                       CcnxPitEntry (Create<CcnxNameComponents> (header.GetName ()),
-                                    Simulator::Now () +
-                                    (header.GetInterestLifetime ().IsZero ()?m_PitEntryDefaultLifetime
-                                     :                                       header.GetInterestLifetime ()),
+                                    header.GetInterestLifetime ().IsZero ()?m_PitEntryDefaultLifetime
+                                    :                                       header.GetInterestLifetime (),
                                     *fibEntry));
 
       // isDuplicate = false; // redundant