Modified CcnxConsumer: retransmission after NACK or default timeout
diff --git a/apps/ccnx-consumer.cc b/apps/ccnx-consumer.cc
index dc54f92..27891b1 100644
--- a/apps/ccnx-consumer.cc
+++ b/apps/ccnx-consumer.cc
@@ -34,6 +34,11 @@
#include "ns3/ccnx-content-object-header.h"
#include <boost/ref.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+
+namespace ll = boost::lambda;
NS_LOG_COMPONENT_DEFINE ("CcnxConsumer");
@@ -48,6 +53,11 @@
static TypeId tid = TypeId ("ns3::CcnxConsumer")
.SetParent<Application> ()
.AddConstructor<CcnxConsumer> ()
+ .AddAttribute ("StartSeq", "Initial sequence number",
+ IntegerValue(0),
+ MakeIntegerAccessor(&CcnxConsumer::m_seq),
+ MakeIntegerChecker<int32_t>())
+
.AddAttribute ("OffTime", "Time interval between packets",
StringValue ("100ms"),
MakeTimeAccessor (&CcnxConsumer::m_offTime),
@@ -76,13 +86,23 @@
CcnxNameComponentsValue (),
MakeCcnxNameComponentsAccessor (&CcnxConsumer::m_exclude),
MakeCcnxNameComponentsChecker ())
- // .AddAttribute ("Initial Nonce", "If 0 then nonce is not used",
- // UintegerValue(1),
- // MakeUintegerAccessor(&CcnxConsumer::m_initialNonce),
- // MakeUintegerChecker<uint32_t>())
+
+ .AddAttribute ("RTO",
+ "Initial retransmission timeout",
+ StringValue ("1s"),
+ MakeTimeAccessor (&CcnxConsumer::m_rto),
+ MakeTimeChecker ())
+ .AddAttribute ("RetxTimer",
+ "Timeout defining how frequent retransmission timeouts should be checked",
+ StringValue ("1s"),
+ MakeTimeAccessor (&CcnxConsumer::GetRetxTimer, &CcnxConsumer::SetRetxTimer),
+ MakeTimeChecker ())
+
// .AddTraceSource ("InterestTrace", "Interests that were sent",
// MakeTraceSourceAccessor (&CcnxConsumer::m_interestsTrace))
- // .AddTraceSource ("ContentObjectTrace", "ContentObjects that were received",
+ // .AddTraceSource ("NackTrace", "NACKs received",
+ // MakeTraceSourceAccessor (&CcnxConsumer::m_nackTrace))
+ // .AddTraceSource ("ContentObjectTrace", "ContentObjects received",
// MakeTraceSourceAccessor (&CcnxConsumer::m_contentObjectsTrace))
;
@@ -95,7 +115,48 @@
{
NS_LOG_FUNCTION_NOARGS ();
}
-
+
+void
+CcnxConsumer::SetRetxTimer (Time retxTimer)
+{
+ m_retxTimer = retxTimer;
+ if (m_retxEvent.IsRunning ())
+ m_retxEvent.Cancel (); // cancel any scheduled cleanup events
+
+ // schedule even with new timeout
+ m_retxEvent = Simulator::Schedule (m_retxTimer,
+ &CcnxConsumer::CheckRetxTimeout, this);
+}
+
+Time
+CcnxConsumer::GetRetxTimer () const
+{
+ return m_retxTimer;
+}
+
+void
+CcnxConsumer::CheckRetxTimeout ()
+{
+ Time now = Simulator::Now ();
+
+ while (!m_seqTimeouts.empty ())
+ {
+ SeqTimeoutsContainer::index<i_timestamp>::type::iterator entry =
+ m_seqTimeouts.get<i_timestamp> ().begin ();
+ if (entry->time + m_rto <= now) // timeout expired?
+ {
+ m_retxSeqs.insert (entry->seq);
+ m_seqTimeouts.get<i_timestamp> ().modify (entry,
+ ll::bind(&SeqTimeout::time, ll::_1) = now);
+ }
+ else
+ break; // nothing else to do. All later packets need not be retransmitted
+ }
+
+ m_retxEvent = Simulator::Schedule (m_retxTimer,
+ &CcnxConsumer::CheckRetxTimeout, this);
+}
+
// Application Methods
void
CcnxConsumer::StartApplication () // Called at time specified by Start
@@ -125,10 +186,20 @@
CcnxConsumer::SendPacket ()
{
NS_LOG_FUNCTION_NOARGS ();
-
+
+ uint32_t seq;
+
+ if (m_retxSeqs.size () != 0)
+ {
+ seq = *m_retxSeqs.begin ();
+ m_retxSeqs.erase (m_retxSeqs.begin ());
+ }
+ else
+ seq = m_seq++;
+
//
Ptr<CcnxNameComponents> nameWithSequence = Create<CcnxNameComponents> (m_interestName);
- (*nameWithSequence) (m_seq++);
+ (*nameWithSequence) (seq);
//
CcnxInterestHeader interestHeader;
@@ -143,14 +214,23 @@
interestHeader.SetMaxSuffixComponents (m_maxSuffixComponents);
interestHeader.SetMinSuffixComponents (m_minSuffixComponents);
- NS_LOG_INFO ("Requesting Interest: \n" << interestHeader);
+ // NS_LOG_INFO ("Requesting Interest: \n" << interestHeader);
+ NS_LOG_INFO ("> Interest for " << seq);
Ptr<Packet> packet = Create<Packet> ();
packet->AddHeader (interestHeader);
m_protocolHandler (packet);
-
+
+ std::pair<SeqTimeoutsContainer::iterator, bool>
+ res = m_seqTimeouts.insert (SeqTimeout (seq, Simulator::Now ()));
+ if (!res.second)
+ m_seqTimeouts.modify (res.first,
+ ll::bind(&SeqTimeout::time, ll::_1) = Simulator::Now ());
+
m_sendEvent = Simulator::Schedule (m_offTime, &CcnxConsumer::SendPacket, this);
+
+ // \todo Trace
}
void
@@ -159,7 +239,35 @@
{
NS_LOG_FUNCTION (this << contentObject << payload);
- NS_LOG_INFO ("Received content object: " << boost::cref(*contentObject));
+ // NS_LOG_INFO ("Received content object: " << boost::cref(*contentObject));
+
+ uint32_t seq = boost::lexical_cast<uint32_t> (contentObject->GetName ().GetComponents ().back ());
+ NS_LOG_INFO ("< DATA for " << seq);
+
+ SeqTimeoutsContainer::iterator entry = m_seqTimeouts.find (seq);
+
+ NS_ASSERT_MSG (entry != m_seqTimeouts.end (),
+ "Comment out this assert, if it causes problems");
+
+ if (entry != m_seqTimeouts.end ())
+ m_seqTimeouts.erase (entry);
+
+ // \todo Trace
+}
+
+void
+CcnxConsumer::OnNack (const Ptr<const CcnxInterestHeader> &interest)
+{
+ NS_LOG_FUNCTION (this << interest);
+
+ // NS_LOG_INFO ("Received NACK: " << boost::cref(*interest));
+ uint32_t seq = boost::lexical_cast<uint32_t> (interest->GetName ().GetComponents ().back ());
+ NS_LOG_INFO ("< NACK for " << seq);
+
+ // put in the queue of interests to be retransmitted
+ m_retxSeqs.insert (seq);
+
+ // \todo Trace?
}
} // namespace ns3
diff --git a/apps/ccnx-consumer.h b/apps/ccnx-consumer.h
index 792c829..ce0a20c 100644
--- a/apps/ccnx-consumer.h
+++ b/apps/ccnx-consumer.h
@@ -24,6 +24,14 @@
#include "ccnx-app.h"
#include "ns3/random-variable.h"
#include "ns3/ccnx-name-components.h"
+#include "ns3/nstime.h"
+
+#include <set>
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/tag.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/member.hpp>
namespace ns3
{
@@ -35,8 +43,16 @@
CcnxConsumer ();
- void OnContentObject (const Ptr<const CcnxContentObjectHeader> &contentObject,
- const Ptr<const Packet> &payload);
+ // From CcnxApp
+ // virtual void
+ // OnInterest (const Ptr<const CcnxInterestHeader> &interest);
+
+ virtual void
+ OnNack (const Ptr<const CcnxInterestHeader> &interest);
+
+ virtual void
+ OnContentObject (const Ptr<const CcnxContentObjectHeader> &contentObject,
+ const Ptr<const Packet> &payload);
protected:
// from CcnxApp
@@ -48,13 +64,29 @@
private:
//helpers
- void SendPacket ();
-
-private:
+ void
+ SendPacket ();
+
+ void
+ CheckRetxTimeout ();
+
+ void
+ SetRetxTimer (Time retxTimer);
+
+ Time
+ GetRetxTimer () const;
+
+protected:
UniformVariable m_rand;
uint32_t m_seq;
EventId m_sendEvent; // Eventid of pending "send packet" event
+ Time m_retxTimer;
+ EventId m_retxEvent; // Event to check whether or not retransmission should be performed
+ Time m_rto; // Retransmission timeout
+ Time m_rttVar; // RTT variance
+ Time m_sRtt; // smoothed RTT
+
Time m_offTime;
CcnxNameComponents m_interestName;
Time m_interestLifeTime;
@@ -62,6 +94,41 @@
int32_t m_maxSuffixComponents;
bool m_childSelector;
CcnxNameComponents m_exclude;
+
+ struct RetxSeqsContainer :
+ public std::set<uint32_t> { };
+
+ RetxSeqsContainer m_retxSeqs; // ordered set of sequence numbers to be retransmitted
+
+ struct SeqTimeout
+ {
+ SeqTimeout (uint32_t _seq, Time _time) : seq (_seq), time (_time) { }
+
+ uint32_t seq;
+ Time time;
+
+ bool operator < (const SeqTimeout &st) { return time < st.time || (time == st.time && seq < st.seq); }
+ };
+
+ class i_seq { };
+ class i_timestamp { };
+
+ struct SeqTimeoutsContainer :
+ public boost::multi_index::multi_index_container<
+ SeqTimeout,
+ boost::multi_index::indexed_by<
+ boost::multi_index::ordered_unique<
+ boost::multi_index::tag<i_seq>,
+ boost::multi_index::member<SeqTimeout, uint32_t, &SeqTimeout::seq>
+ >,
+ boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<i_timestamp>,
+ boost::multi_index::member<SeqTimeout, Time, &SeqTimeout::time>
+ >
+ >
+ > { } ;
+
+ SeqTimeoutsContainer m_seqTimeouts;
};
} // namespace ns3