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