diff --git a/CHANGES.html b/CHANGES.html
index be0f827b6..c9078c015 100644
--- a/CHANGES.html
+++ b/CHANGES.html
@@ -74,6 +74,7 @@ allows to choose between Block Ack policy and Implicit Block Ack Request policy
allows to request an acknowledgment after a configurable number of MPDUs have been
transmitted.
The MaxSize attribute is removed from the QueueBase base class and moved to subclasses. A new MaxSize attribute is therefore added to the DropTailQueue class, while the MaxQueueSize attribute of the WifiMacQueue class is renamed as MaxSize for API consistency.
+ TCP-based applications (OnOffApplication, BulkSendApplication, and PacketSink) support a new header to convey sequence number, timestamp, and size data. Use is controlled by the "EnableSeqTsSizeHeader" attribute.
Added a new trace source PhyRxPayloadBegin in WifiPhy for tracing begin of PSDU reception.
A new sequence and timestamp header variant for applications has been added. The SeqTsEchoHeader contains an additional timestamp field for use in echoing a timestamp back to a sender.
diff --git a/src/applications/model/bulk-send-application.cc b/src/applications/model/bulk-send-application.cc
index 44a463427..f7dbc2e4b 100644
--- a/src/applications/model/bulk-send-application.cc
+++ b/src/applications/model/bulk-send-application.cc
@@ -70,17 +70,17 @@ BulkSendApplication::GetTypeId (void)
TypeIdValue (TcpSocketFactory::GetTypeId ()),
MakeTypeIdAccessor (&BulkSendApplication::m_tid),
MakeTypeIdChecker ())
- .AddAttribute ("EnableE2EStats",
- "Enable E2E statistics (sequences, timestamps)",
+ .AddAttribute ("EnableSeqTsSizeHeader",
+ "Add SeqTsSizeHeader to each packet",
BooleanValue (false),
- MakeBooleanAccessor (&BulkSendApplication::m_enableE2EStats),
+ MakeBooleanAccessor (&BulkSendApplication::m_enableSeqTsSizeHeader),
MakeBooleanChecker ())
- .AddTraceSource ("Tx", "A new packet is created and is sent",
+ .AddTraceSource ("Tx", "A new packet is sent",
MakeTraceSourceAccessor (&BulkSendApplication::m_txTrace),
"ns3::Packet::TracedCallback")
- .AddTraceSource ("TxE2EStat", "Statistic sent with the packet",
- MakeTraceSourceAccessor (&BulkSendApplication::m_txTraceWithStats),
- "ns3::PacketSink::E2EStatCallback")
+ .AddTraceSource ("TxWithSeqTsSize", "A new packet is created with SeqTsSizeHeader",
+ MakeTraceSourceAccessor (&BulkSendApplication::m_txTraceWithSeqTsSize),
+ "ns3::PacketSink::SeqTsSizeCallback")
;
return tid;
}
@@ -89,7 +89,8 @@ BulkSendApplication::GetTypeId (void)
BulkSendApplication::BulkSendApplication ()
: m_socket (0),
m_connected (false),
- m_totBytes (0)
+ m_totBytes (0),
+ m_unsentPacket (0)
{
NS_LOG_FUNCTION (this);
}
@@ -119,6 +120,7 @@ BulkSendApplication::DoDispose (void)
NS_LOG_FUNCTION (this);
m_socket = 0;
+ m_unsentPacket = 0;
// chain up
Application::DoDispose ();
}
@@ -221,16 +223,20 @@ void BulkSendApplication::SendData (const Address &from, const Address &to)
NS_LOG_LOGIC ("sending packet at " << Simulator::Now ());
Ptr packet;
- if (m_enableE2EStats)
+ if (m_unsentPacket)
{
- // Should we add a trace for the sent tx and timestamp?
- E2eStatsHeader header;
+ packet = m_unsentPacket;
+ }
+ else if (m_enableSeqTsSizeHeader)
+ {
+ SeqTsSizeHeader header;
header.SetSeq (m_seq++);
header.SetSize (toSend);
NS_ABORT_IF (toSend < header.GetSerializedSize ());
packet = Create (toSend - header.GetSerializedSize ());
+ // Trace before adding header, for consistency with PacketSink
+ m_txTraceWithSeqTsSize (packet, from, to, header);
packet->AddHeader (header);
- m_txTraceWithStats (packet, from, to, header);
}
else
{
@@ -238,18 +244,25 @@ void BulkSendApplication::SendData (const Address &from, const Address &to)
}
int actual = m_socket->Send (packet);
- if (actual > 0)
+ if ((unsigned) actual == toSend)
{
m_totBytes += actual;
m_txTrace (packet);
+ m_unsentPacket = 0;
}
- // We exit this loop when actual < toSend as the send side
- // buffer is full. The "DataSent" callback will pop when
- // some buffer space has freed up.
- if ((unsigned)actual != toSend)
+ else if (actual == -1)
{
+ // We exit this loop when actual < toSend as the send side
+ // buffer is full. The "DataSent" callback will pop when
+ // some buffer space has freed up.
+ NS_LOG_DEBUG ("Unable to send packet; caching for later attempt");
+ m_unsentPacket = packet;
break;
}
+ else
+ {
+ NS_FATAL_ERROR ("Unexpected return value from m_socket->Send ()");
+ }
}
// Check if time to close (all sent)
if (m_totBytes == m_maxBytes && m_connected)
diff --git a/src/applications/model/bulk-send-application.h b/src/applications/model/bulk-send-application.h
index 544ef8414..4d8aa5c96 100644
--- a/src/applications/model/bulk-send-application.h
+++ b/src/applications/model/bulk-send-application.h
@@ -26,7 +26,7 @@
#include "ns3/event-id.h"
#include "ns3/ptr.h"
#include "ns3/traced-callback.h"
-#include "ns3/e2e-stats-header.h"
+#include "ns3/seq-ts-size-header.h"
namespace ns3 {
@@ -65,12 +65,12 @@ class Socket;
* For example, TCP sockets can be used, but
* UDP sockets can not be used.
*
- * If the attribute "EnableE2EStats" is enabled, the application will use
- * some byte of the payload to store an header with a sequence number,
- * a timestamp, and the size of the packet sent. To get these statistics,
- * please use PacketSink (and enable its "EnableE2EStats" attribute) or extract
- * the header yourself in your application (you can see how PacketSink is working
- * with such headers).
+ * If the attribute "EnableSeqTsSizeHeader" is enabled, the application will
+ * use some bytes of the payload to store an header with a sequence number,
+ * a timestamp, and the size of the packet sent. Support for extracting
+ * statistics from this header have been added to \c ns3::PacketSink
+ * (enable its "EnableSeqTsSizeHeader" attribute), or users may extract
+ * the header via trace sources.
*/
class BulkSendApplication : public Application
{
@@ -129,14 +129,14 @@ private:
uint64_t m_totBytes; //!< Total bytes sent so far
TypeId m_tid; //!< The type of protocol to use.
uint32_t m_seq {0}; //!< Sequence
- bool m_enableE2EStats {false}; //!< Enable or disable the e2e statistic generation
-
+ Ptr m_unsentPacket; //!< Variable to cache unsent packet
+ bool m_enableSeqTsSizeHeader {false}; //!< Enable or disable the SeqTsSizeHeader
/// Traced Callback: sent packets
TracedCallback > m_txTrace;
- /// Callback for tracing the packet Tx events, includes source, destination, and the packet sent
- TracedCallback, const Address &, const Address &, const E2eStatsHeader &> m_txTraceWithStats;
+ /// Callback for tracing the packet Tx events, includes source, destination, the packet sent, and header
+ TracedCallback, const Address &, const Address &, const SeqTsSizeHeader &> m_txTraceWithSeqTsSize;
private:
/**
diff --git a/src/applications/model/onoff-application.cc b/src/applications/model/onoff-application.cc
index 166612e61..d4d546308 100644
--- a/src/applications/model/onoff-application.cc
+++ b/src/applications/model/onoff-application.cc
@@ -94,10 +94,10 @@ OnOffApplication::GetTypeId (void)
MakeTypeIdAccessor (&OnOffApplication::m_tid),
// This should check for SocketFactory as a parent
MakeTypeIdChecker ())
- .AddAttribute ("EnableE2EStats",
- "Enable E2E statistics (sequences, timestamps)",
+ .AddAttribute ("EnableSeqTsSizeHeader",
+ "Enable use of SeqTsSizeHeader for sequence number and timestamp",
BooleanValue (false),
- MakeBooleanAccessor (&OnOffApplication::m_enableE2EStats),
+ MakeBooleanAccessor (&OnOffApplication::m_enableSeqTsSizeHeader),
MakeBooleanChecker ())
.AddTraceSource ("Tx", "A new packet is created and is sent",
MakeTraceSourceAccessor (&OnOffApplication::m_txTrace),
@@ -105,9 +105,9 @@ OnOffApplication::GetTypeId (void)
.AddTraceSource ("TxWithAddresses", "A new packet is created and is sent",
MakeTraceSourceAccessor (&OnOffApplication::m_txTraceWithAddresses),
"ns3::Packet::TwoAddressTracedCallback")
- .AddTraceSource ("TxE2EStat", "Statistic sent with the packet",
- MakeTraceSourceAccessor (&OnOffApplication::m_txTraceWithStats),
- "ns3::PacketSink::E2EStatCallback")
+ .AddTraceSource ("TxWithSeqTsSize", "A new packet is created with SeqTsSizeHeader",
+ MakeTraceSourceAccessor (&OnOffApplication::m_txTraceWithSeqTsSize),
+ "ns3::PacketSink::SeqTsSizeCallback")
;
return tid;
}
@@ -118,7 +118,8 @@ OnOffApplication::OnOffApplication ()
m_connected (false),
m_residualBits (0),
m_lastStartTime (Seconds (0)),
- m_totBytes (0)
+ m_totBytes (0),
+ m_unsentPacket (0)
{
NS_LOG_FUNCTION (this);
}
@@ -158,6 +159,7 @@ OnOffApplication::DoDispose (void)
CancelEvents ();
m_socket = 0;
+ m_unsentPacket = 0;
// chain up
Application::DoDispose ();
}
@@ -245,6 +247,13 @@ void OnOffApplication::CancelEvents ()
m_cbrRateFailSafe = m_cbrRate;
Simulator::Cancel (m_sendEvent);
Simulator::Cancel (m_startStopEvent);
+ // Canceling events may cause discontinuity in sequence number if the
+ // SeqTsSizeHeader is header, and m_unsentPacket is true
+ if (m_unsentPacket)
+ {
+ NS_LOG_DEBUG ("Discarding cached packet upon CancelEvents ()");
+ }
+ m_unsentPacket = 0;
}
// Event handlers
@@ -271,17 +280,19 @@ void OnOffApplication::ScheduleNextTx ()
if (m_maxBytes == 0 || m_totBytes < m_maxBytes)
{
+ NS_ABORT_MSG_IF (m_residualBits > m_pktSize * 8, "Calculation to compute next send time will overflow");
uint32_t bits = m_pktSize * 8 - m_residualBits;
NS_LOG_LOGIC ("bits = " << bits);
Time nextTime (Seconds (bits /
static_cast(m_cbrRate.GetBitRate ()))); // Time till next packet
- NS_LOG_LOGIC ("nextTime = " << nextTime);
+ NS_LOG_LOGIC ("nextTime = " << nextTime.As (Time::S));
m_sendEvent = Simulator::Schedule (nextTime,
&OnOffApplication::SendPacket, this);
}
else
{ // All done, cancel any pending events
StopApplication ();
+ exit(1);
}
}
@@ -290,7 +301,7 @@ void OnOffApplication::ScheduleStartEvent ()
NS_LOG_FUNCTION (this);
Time offInterval = Seconds (m_offTime->GetValue ());
- NS_LOG_LOGIC ("start at " << offInterval);
+ NS_LOG_LOGIC ("start at " << offInterval.As (Time::S));
m_startStopEvent = Simulator::Schedule (offInterval, &OnOffApplication::StartSending, this);
}
@@ -299,7 +310,7 @@ void OnOffApplication::ScheduleStopEvent ()
NS_LOG_FUNCTION (this);
Time onInterval = Seconds (m_onTime->GetValue ());
- NS_LOG_LOGIC ("stop at " << onInterval);
+ NS_LOG_LOGIC ("stop at " << onInterval.As (Time::S));
m_startStopEvent = Simulator::Schedule (onInterval, &OnOffApplication::StopSending, this);
}
@@ -311,51 +322,65 @@ void OnOffApplication::SendPacket ()
NS_ASSERT (m_sendEvent.IsExpired ());
Ptr packet;
- if (m_enableE2EStats)
+ if (m_unsentPacket)
+ {
+ packet = m_unsentPacket;
+ }
+ else if (m_enableSeqTsSizeHeader)
{
Address from, to;
m_socket->GetSockName (from);
m_socket->GetPeerName (to);
- E2eStatsHeader header;
+ SeqTsSizeHeader header;
header.SetSeq (m_seq++);
header.SetSize (m_pktSize);
NS_ABORT_IF (m_pktSize < header.GetSerializedSize ());
packet = Create (m_pktSize - header.GetSerializedSize ());
+ // Trace before adding header, for consistency with PacketSink
+ m_txTraceWithSeqTsSize (packet, from, to, header);
packet->AddHeader (header);
- m_txTraceWithStats (packet, from, to, header);
}
else
{
packet = Create (m_pktSize);
}
- m_txTrace (packet);
- m_socket->Send (packet);
- m_totBytes += m_pktSize;
- Address localAddress;
- m_socket->GetSockName (localAddress);
- if (InetSocketAddress::IsMatchingType (m_peer))
+ int actual = m_socket->Send (packet);
+ if ((unsigned) actual == m_pktSize)
{
- NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds ()
- << "s on-off application sent "
- << packet->GetSize () << " bytes to "
- << InetSocketAddress::ConvertFrom(m_peer).GetIpv4 ()
- << " port " << InetSocketAddress::ConvertFrom (m_peer).GetPort ()
- << " total Tx " << m_totBytes << " bytes");
- m_txTraceWithAddresses (packet, localAddress, InetSocketAddress::ConvertFrom (m_peer));
+ m_txTrace (packet);
+ m_totBytes += m_pktSize;
+ m_unsentPacket = 0;
+ Address localAddress;
+ m_socket->GetSockName (localAddress);
+ if (InetSocketAddress::IsMatchingType (m_peer))
+ {
+ NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds ()
+ << "s on-off application sent "
+ << packet->GetSize () << " bytes to "
+ << InetSocketAddress::ConvertFrom(m_peer).GetIpv4 ()
+ << " port " << InetSocketAddress::ConvertFrom (m_peer).GetPort ()
+ << " total Tx " << m_totBytes << " bytes");
+ m_txTraceWithAddresses (packet, localAddress, InetSocketAddress::ConvertFrom (m_peer));
+ }
+ else if (Inet6SocketAddress::IsMatchingType (m_peer))
+ {
+ NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds ()
+ << "s on-off application sent "
+ << packet->GetSize () << " bytes to "
+ << Inet6SocketAddress::ConvertFrom(m_peer).GetIpv6 ()
+ << " port " << Inet6SocketAddress::ConvertFrom (m_peer).GetPort ()
+ << " total Tx " << m_totBytes << " bytes");
+ m_txTraceWithAddresses (packet, localAddress, Inet6SocketAddress::ConvertFrom(m_peer));
+ }
}
- else if (Inet6SocketAddress::IsMatchingType (m_peer))
+ else
{
- NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds ()
- << "s on-off application sent "
- << packet->GetSize () << " bytes to "
- << Inet6SocketAddress::ConvertFrom(m_peer).GetIpv6 ()
- << " port " << Inet6SocketAddress::ConvertFrom (m_peer).GetPort ()
- << " total Tx " << m_totBytes << " bytes");
- m_txTraceWithAddresses (packet, localAddress, Inet6SocketAddress::ConvertFrom(m_peer));
+ NS_LOG_DEBUG ("Unable to send packet; actual " << actual << " size " << m_pktSize << "; caching for later attempt");
+ m_unsentPacket = packet;
}
- m_lastStartTime = Simulator::Now ();
m_residualBits = 0;
+ m_lastStartTime = Simulator::Now ();
ScheduleNextTx ();
}
diff --git a/src/applications/model/onoff-application.h b/src/applications/model/onoff-application.h
index 90711c1a0..3aba54514 100644
--- a/src/applications/model/onoff-application.h
+++ b/src/applications/model/onoff-application.h
@@ -31,7 +31,7 @@
#include "ns3/ptr.h"
#include "ns3/data-rate.h"
#include "ns3/traced-callback.h"
-#include "ns3/e2e-stats-header.h"
+#include "ns3/seq-ts-size-header.h"
namespace ns3 {
@@ -84,12 +84,13 @@ class Socket;
* If the underlying socket type supports broadcast, this application
* will automatically enable the SetAllowBroadcast(true) socket option.
*
-* If the attribute "EnableE2EStats" is enabled, the application will use
-* some byte of the payload to store an header with a sequence number,
-* a timestamp, and the size of the packet sent. To get these statistics,
-* please use PacketSink (and enable its "EnableE2EStats" attribute) or extract
-* the header yourself in your application (you can see how PacketSink is working
-* with such headers).
+ * If the attribute "EnableSeqTsSizeHeader" is enabled, the application will
+ * use some bytes of the payload to store an header with a sequence number,
+ * a timestamp, and the size of the packet sent. Support for extracting
+ * statistics from this header have been added to \c ns3::PacketSink
+ * (enable its "EnableSeqTsSizeHeader" attribute), or users may extract
+ * the header via trace sources. Note that the continuity of the sequence
+ * number may be disrupted across On/Off cycles.
*/
class OnOffApplication : public Application
{
@@ -173,7 +174,8 @@ private:
EventId m_sendEvent; //!< Event id of pending "send packet" event
TypeId m_tid; //!< Type of the socket used
uint32_t m_seq {0}; //!< Sequence
- bool m_enableE2EStats {false}; //!< Enable or disable the e2e statistic generation
+ Ptr m_unsentPacket; //!< Unsent packet cached for future attempt
+ bool m_enableSeqTsSizeHeader {false}; //!< Enable or disable the use of SeqTsSizeHeader
/// Traced Callback: transmitted packets.
@@ -182,8 +184,8 @@ private:
/// Callbacks for tracing the packet Tx events, includes source and destination addresses
TracedCallback, const Address &, const Address &> m_txTraceWithAddresses;
- /// Callback for tracing the packet Tx events, includes source, destination, and the packet sent
- TracedCallback, const Address &, const Address &, const E2eStatsHeader &> m_txTraceWithStats;
+ /// Callback for tracing the packet Tx events, includes source, destination, the packet sent, and header
+ TracedCallback, const Address &, const Address &, const SeqTsSizeHeader &> m_txTraceWithSeqTsSize;
private:
/**
diff --git a/src/applications/model/packet-sink.cc b/src/applications/model/packet-sink.cc
index 16c539834..a1c6a7cb4 100644
--- a/src/applications/model/packet-sink.cc
+++ b/src/applications/model/packet-sink.cc
@@ -56,10 +56,10 @@ PacketSink::GetTypeId (void)
TypeIdValue (UdpSocketFactory::GetTypeId ()),
MakeTypeIdAccessor (&PacketSink::m_tid),
MakeTypeIdChecker ())
- .AddAttribute ("EnableE2EStats",
- "Enable E2E statistics (sequences, timestamps)",
+ .AddAttribute ("EnableSeqTsSizeHeader",
+ "Enable optional header tracing of SeqTsSizeHeader",
BooleanValue (false),
- MakeBooleanAccessor (&PacketSink::m_enableE2EStats),
+ MakeBooleanAccessor (&PacketSink::m_enableSeqTsSizeHeader),
MakeBooleanChecker ())
.AddTraceSource ("Rx",
"A packet has been received",
@@ -68,10 +68,10 @@ PacketSink::GetTypeId (void)
.AddTraceSource ("RxWithAddresses", "A packet has been received",
MakeTraceSourceAccessor (&PacketSink::m_rxTraceWithAddresses),
"ns3::Packet::TwoAddressTracedCallback")
- .AddTraceSource ("RxE2EStat",
- "A sequence number and a timestamp have been received",
- MakeTraceSourceAccessor (&PacketSink::m_rxTraceWithAddressesAndSeqTs),
- "ns3::PacketSink::E2EStatCallback")
+ .AddTraceSource ("RxWithSeqTsSize",
+ "A packet with SeqTsSize header has been received",
+ MakeTraceSourceAccessor (&PacketSink::m_rxTraceWithSeqTsSize),
+ "ns3::PacketSink::SeqTsSizeCallback")
;
return tid;
}
@@ -208,7 +208,7 @@ void PacketSink::HandleRead (Ptr socket)
m_rxTrace (packet, from);
m_rxTraceWithAddresses (packet, from, localAddress);
- if (m_enableE2EStats)
+ if (m_enableSeqTsSizeHeader)
{
PacketReceived (packet, from, localAddress);
}
@@ -219,7 +219,7 @@ void
PacketSink::PacketReceived (const Ptr &p, const Address &from,
const Address &localAddress)
{
- E2eStatsHeader header;
+ SeqTsSizeHeader header;
Ptr buffer;
auto itBuffer = m_buffer.find (from);
@@ -236,14 +236,15 @@ PacketSink::PacketReceived (const Ptr &p, const Address &from,
while (buffer->GetSize () >= header.GetSize ())
{
+ NS_LOG_DEBUG ("Removing packet of size " << header.GetSize () << " from buffer of size " << buffer->GetSize ());
Ptr complete = buffer->CreateFragment (0, static_cast (header.GetSize ()));
buffer->RemoveAtStart (static_cast (header.GetSize ()));
complete->RemoveHeader (header);
- m_rxTraceWithAddressesAndSeqTs (complete, from, localAddress, header);
+ m_rxTraceWithSeqTsSize (complete, from, localAddress, header);
- if (buffer->GetSize () > 0)
+ if (buffer->GetSize () > header.GetSerializedSize ())
{
buffer->PeekHeader (header);
}
@@ -254,7 +255,6 @@ PacketSink::PacketReceived (const Ptr &p, const Address &from,
}
}
-
void PacketSink::HandlePeerClose (Ptr socket)
{
NS_LOG_FUNCTION (this << socket);
@@ -264,7 +264,6 @@ void PacketSink::HandlePeerError (Ptr socket)
{
NS_LOG_FUNCTION (this << socket);
}
-
void PacketSink::HandleAccept (Ptr s, const Address& from)
{
diff --git a/src/applications/model/packet-sink.h b/src/applications/model/packet-sink.h
index b583bcdaa..7f938a0f2 100644
--- a/src/applications/model/packet-sink.h
+++ b/src/applications/model/packet-sink.h
@@ -27,7 +27,7 @@
#include "ns3/traced-callback.h"
#include "ns3/address.h"
#include "ns3/inet-socket-address.h"
-#include "ns3/e2e-stats-header.h"
+#include "ns3/seq-ts-size-header.h"
#include
namespace ns3 {
@@ -96,16 +96,15 @@ public:
std::list > GetAcceptedSockets (void) const;
/**
- * TracedCallback signature for an E2E stat callback
+ * TracedCallback signature for a reception with addresses and SeqTsSizeHeader
*
- * \param p The packet received
+ * \param p The packet received (without the SeqTsSize header)
* \param from From address
* \param to Local address
- * \param seq The sequence received
- * \param time The delay the sequence has needed from the sender to the receiver
+ * \param header The SeqTsSize header
*/
- typedef void (* E2EStatCallback)(Ptr p, const Address &from, const Address & to,
- const E2eStatsHeader &header);
+ typedef void (* SeqTsSizeCallback)(Ptr p, const Address &from, const Address & to,
+ const SeqTsSizeHeader &header);
protected:
virtual void DoDispose (void);
@@ -137,14 +136,13 @@ private:
void HandlePeerError (Ptr socket);
/**
- * \brief Packet received: calculation of the e2e statistics
+ * \brief Packet received: assemble byte stream to extract SeqTsSizeHeader
* \param p received packet
* \param from from address
* \param localAddress local address
*
- * The method calculates e2e statistics about the received packet. If
- * the transport protocol is stream-based, then reconstruct first the
- * original packet, and then extract the statistic header from it.
+ * The method assembles a received byte stream and extracts SeqTsSizeHeader
+ * instances from the stream to export in a trace source.
*/
void PacketReceived (const Ptr &p, const Address &from, const Address &localAddress);
@@ -182,14 +180,14 @@ private:
uint64_t m_totalRx; //!< Total bytes received
TypeId m_tid; //!< Protocol TypeId
- bool m_enableE2EStats {false}; //!< Enable or disable the E2E statistics generation
+ bool m_enableSeqTsSizeHeader {false}; //!< Enable or disable the export of SeqTsSize header
/// Traced Callback: received packets, source address.
TracedCallback, const Address &> m_rxTrace;
/// Callback for tracing the packet Rx events, includes source and destination addresses
TracedCallback, const Address &, const Address &> m_rxTraceWithAddresses;
- /// Callback for tracing the packet Rx events, includes source, destination addresses, sequence and timestamp
- TracedCallback, const Address &, const Address &, const E2eStatsHeader&> m_rxTraceWithAddressesAndSeqTs;
+ /// Callbacks for tracing the packet Rx events, includes source, destination addresses, and headers
+ TracedCallback, const Address &, const Address &, const SeqTsSizeHeader&> m_rxTraceWithSeqTsSize;
};
} // namespace ns3
diff --git a/src/applications/model/seq-ts-echo-header.cc b/src/applications/model/seq-ts-echo-header.cc
index d211b9a8a..0a8e3188a 100644
--- a/src/applications/model/seq-ts-echo-header.cc
+++ b/src/applications/model/seq-ts-echo-header.cc
@@ -1,6 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2016 Universita' di Firenze
+ * Copyright (c) 2009 INRIA
+ * Copyright (c) 2016 Universita' di Firenze (added echo fields)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -55,7 +56,7 @@ SeqTsEchoHeader::GetSeq (void) const
void
SeqTsEchoHeader::SetTsValue (Time ts)
{
- NS_LOG_FUNCTION (this);
+ NS_LOG_FUNCTION (this << ts);
m_tsValue = ts;
}
@@ -69,7 +70,7 @@ SeqTsEchoHeader::GetTsValue (void) const
void
SeqTsEchoHeader::SetTsEchoReply (Time ts)
{
- NS_LOG_FUNCTION (this);
+ NS_LOG_FUNCTION (this << ts);
m_tsEchoReply = ts;
}
diff --git a/src/applications/model/seq-ts-echo-header.h b/src/applications/model/seq-ts-echo-header.h
index 662d60885..203c3281e 100644
--- a/src/applications/model/seq-ts-echo-header.h
+++ b/src/applications/model/seq-ts-echo-header.h
@@ -1,6 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2016 Universita' di Firenze
+ * Copyright (c) 2009 INRIA
+ * Copyright (c) 2016 Universita' di Firenze (added echo fields)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/applications/model/seq-ts-header.h b/src/applications/model/seq-ts-header.h
index add229d37..938f07bc8 100644
--- a/src/applications/model/seq-ts-header.h
+++ b/src/applications/model/seq-ts-header.h
@@ -26,13 +26,20 @@
namespace ns3 {
/**
- * \ingroup udpclientserver
+ * \ingroup applications
*
- * \brief Packet header for UDP client/server application.
+ * \brief Packet header to carry sequence number and timestamp
*
- * The header is made of a 32bits sequence number followed by
- * a 64bits time stamp. If you need to use this header with a transport protocol
- * such as TCP, please consider to use SizeHeader.
+ * The header is used as a payload in applications (typically UDP) to convey
+ * a 32 bit sequence number followed by a 64 bit timestamp (12 bytes total).
+ *
+ * The timestamp is not set explicitly but automatically set to the
+ * simulation time upon creation.
+ *
+ * If you need space for an application data unit size field (e.g. for
+ * stream-based protocols like TCP), use ns3::SeqTsSizeHeader.
+ *
+ * \sa ns3::SeqTsSizeHeader
*/
class SeqTsHeader : public Header
{
diff --git a/src/applications/model/e2e-stats-header.cc b/src/applications/model/seq-ts-size-header.cc
similarity index 66%
rename from src/applications/model/e2e-stats-header.cc
rename to src/applications/model/seq-ts-size-header.cc
index 753b84d54..a25955603 100644
--- a/src/applications/model/e2e-stats-header.cc
+++ b/src/applications/model/seq-ts-size-header.cc
@@ -1,6 +1,8 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright (c) 2009 INRIA
* Copyright (c) 2018 Natale Patriciello
+ * (added timestamp and size fields)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,39 +20,51 @@
*/
#include "ns3/log.h"
-#include "e2e-stats-header.h"
+#include "seq-ts-size-header.h"
namespace ns3 {
-NS_LOG_COMPONENT_DEFINE ("SizeHeader");
+NS_LOG_COMPONENT_DEFINE ("SeqTsSizeHeader");
-NS_OBJECT_ENSURE_REGISTERED (E2eStatsHeader);
+NS_OBJECT_ENSURE_REGISTERED (SeqTsSizeHeader);
-E2eStatsHeader::E2eStatsHeader ()
+SeqTsSizeHeader::SeqTsSizeHeader ()
: SeqTsHeader ()
{
NS_LOG_FUNCTION (this);
}
TypeId
-E2eStatsHeader::GetTypeId (void)
+SeqTsSizeHeader::GetTypeId (void)
{
- static TypeId tid = TypeId ("ns3::SizeHeader")
+ static TypeId tid = TypeId ("ns3::SeqTsSizeHeader")
.SetParent ()
.SetGroupName ("Applications")
- .AddConstructor ()
+ .AddConstructor ()
;
return tid;
}
TypeId
-E2eStatsHeader::GetInstanceTypeId (void) const
+SeqTsSizeHeader::GetInstanceTypeId (void) const
{
return GetTypeId ();
}
void
-E2eStatsHeader::Print (std::ostream &os) const
+SeqTsSizeHeader::SetSize (uint64_t size)
+{
+ m_size = size;
+}
+
+uint64_t
+SeqTsSizeHeader::GetSize (void) const
+{
+ return m_size;
+}
+
+void
+SeqTsSizeHeader::Print (std::ostream &os) const
{
NS_LOG_FUNCTION (this << &os);
os << "(size=" << m_size << ") AND ";
@@ -58,14 +72,13 @@ E2eStatsHeader::Print (std::ostream &os) const
}
uint32_t
-E2eStatsHeader::GetSerializedSize (void) const
+SeqTsSizeHeader::GetSerializedSize (void) const
{
- NS_LOG_FUNCTION (this);
return SeqTsHeader::GetSerializedSize () + 8;
}
void
-E2eStatsHeader::Serialize (Buffer::Iterator start) const
+SeqTsSizeHeader::Serialize (Buffer::Iterator start) const
{
NS_LOG_FUNCTION (this << &start);
Buffer::Iterator i = start;
@@ -74,7 +87,7 @@ E2eStatsHeader::Serialize (Buffer::Iterator start) const
}
uint32_t
-E2eStatsHeader::Deserialize (Buffer::Iterator start)
+SeqTsSizeHeader::Deserialize (Buffer::Iterator start)
{
NS_LOG_FUNCTION (this << &start);
Buffer::Iterator i = start;
diff --git a/src/applications/model/e2e-stats-header.h b/src/applications/model/seq-ts-size-header.h
similarity index 62%
rename from src/applications/model/e2e-stats-header.h
rename to src/applications/model/seq-ts-size-header.h
index f3bdfeb6d..4b5fa49e5 100644
--- a/src/applications/model/e2e-stats-header.h
+++ b/src/applications/model/seq-ts-size-header.h
@@ -1,6 +1,8 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright (c) 2009 INRIA
* Copyright (c) 2018 Natale Patriciello
+ * (added timestamp and size fields)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#pragma once
+#ifndef SEQ_TS_SIZE_HEADER_H
+#define SEQ_TS_SIZE_HEADER_H
#include
@@ -25,17 +28,13 @@ namespace ns3 {
* \ingroup applications
* \brief Header with a sequence, a timestamp, and a "size" attribute
*
- * Sometimes, you would need an header that not only track an application
- * sequence number, or an application timestamp, but also track
- * how big are these application packets.
+ * This header adds a size attribute to the sequence number and timestamp
+ * of class \c SeqTsHeader. The size attribute can be used to track
+ * application data units for stream-based sockets such as TCP.
*
- * This header extends SeqTsHeader, adding space to store the information
- * about the size of these packets.
- *
- * When you will use a protocol like TCP, you will find the answer to the question
- * "isn't SeqTsHeader enough?".
+ * \sa ns3::SeqTsHeader
*/
-class E2eStatsHeader : public SeqTsHeader
+class SeqTsSizeHeader : public SeqTsHeader
{
public:
/**
@@ -45,35 +44,21 @@ public:
static TypeId GetTypeId (void);
/**
- * @brief SizeHeader constructor
+ * \brief constructor
*/
- E2eStatsHeader ();
+ SeqTsSizeHeader ();
/**
- * \brief ~SizeHeader
- *
- * Nothing much to add here
+ * \brief Set the size information that the header will carry
+ * \param size the size
*/
- virtual ~E2eStatsHeader () override
- {
- }
+ void SetSize (uint64_t size);
/**
- * @brief Set the size information that the header will carry
- * @param size the size
+ * \brief Get the size information that the header is carrying
+ * \return the size
*/
- void SetSize (uint64_t size)
- {
- m_size = size;
- }
- /**
- * @brief Get the size information that the header is carrying
- * @return the size
- */
- uint64_t GetSize (void) const
- {
- return m_size;
- }
+ uint64_t GetSize (void) const;
// Inherited
virtual TypeId GetInstanceTypeId (void) const override;
@@ -87,3 +72,5 @@ private:
};
} // namespace ns3
+
+#endif /* SEQ_TS_SIZE_HEADER */
diff --git a/src/applications/test/bulk-send-application-test-suite.cc b/src/applications/test/bulk-send-application-test-suite.cc
new file mode 100644
index 000000000..74a763bd7
--- /dev/null
+++ b/src/applications/test/bulk-send-application-test-suite.cc
@@ -0,0 +1,233 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2020 Tom Henderson (tomh@tomh.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "ns3/test.h"
+#include "ns3/nstime.h"
+#include "ns3/node.h"
+#include "ns3/traced-callback.h"
+#include "ns3/node-container.h"
+#include "ns3/application-container.h"
+#include "ns3/point-to-point-helper.h"
+#include "ns3/string.h"
+#include "ns3/uinteger.h"
+#include "ns3/boolean.h"
+#include "ns3/internet-stack-helper.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-address-helper.h"
+#include "ns3/ipv4-interface-container.h"
+#include "ns3/bulk-send-application.h"
+#include "ns3/bulk-send-helper.h"
+#include "ns3/packet-sink.h"
+#include "ns3/packet-sink-helper.h"
+
+using namespace ns3;
+
+class BulkSendBasicTestCase : public TestCase
+{
+public:
+ BulkSendBasicTestCase ();
+ virtual ~BulkSendBasicTestCase ();
+
+private:
+ virtual void DoRun (void);
+ void SendTx (Ptr p);
+ void ReceiveRx (Ptr p, const Address& addr);
+ uint64_t m_sent {0};
+ uint64_t m_received {0};
+};
+
+BulkSendBasicTestCase::BulkSendBasicTestCase ()
+ : TestCase ("Check a basic 300KB transfer")
+{
+}
+
+BulkSendBasicTestCase::~BulkSendBasicTestCase ()
+{
+}
+
+void
+BulkSendBasicTestCase::SendTx (Ptr p)
+{
+ m_sent += p->GetSize ();
+}
+
+void
+BulkSendBasicTestCase::ReceiveRx (Ptr p, const Address& addr)
+{
+ m_received += p->GetSize ();
+}
+
+void
+BulkSendBasicTestCase::DoRun (void)
+{
+ Ptr sender = CreateObject ();
+ Ptr receiver = CreateObject ();
+ NodeContainer nodes;
+ nodes.Add (sender);
+ nodes.Add (receiver);
+ PointToPointHelper p2pHelper;
+ p2pHelper.SetDeviceAttribute ("DataRate", StringValue ("10Mbps"));
+ p2pHelper.SetChannelAttribute ("Delay", StringValue ("10ms"));
+ NetDeviceContainer devices;
+ devices = p2pHelper.Install (nodes);
+ InternetStackHelper internet;
+ internet.Install (nodes);
+ Ipv4AddressHelper ipv4;
+ ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+ Ipv4InterfaceContainer i = ipv4.Assign (devices);
+ uint16_t port = 9;
+ BulkSendHelper sourceHelper ("ns3::TcpSocketFactory",
+ InetSocketAddress (i.GetAddress (1), port));
+ sourceHelper.SetAttribute ("MaxBytes", UintegerValue (300000));
+ ApplicationContainer sourceApp = sourceHelper.Install (nodes.Get (0));
+ sourceApp.Start (Seconds (0.0));
+ sourceApp.Stop (Seconds (10.0));
+ PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory",
+ InetSocketAddress (Ipv4Address::GetAny (), port));
+ ApplicationContainer sinkApp = sinkHelper.Install (nodes.Get (1));
+ sinkApp.Start (Seconds (0.0));
+ sinkApp.Stop (Seconds (10.0));
+
+ Ptr source = DynamicCast (sourceApp.Get (0));
+ Ptr sink = DynamicCast (sinkApp.Get (0));
+
+ source->TraceConnectWithoutContext ("Tx", MakeCallback (&BulkSendBasicTestCase::SendTx, this));
+ sink->TraceConnectWithoutContext ("Rx", MakeCallback (&BulkSendBasicTestCase::ReceiveRx, this));
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+
+ NS_TEST_ASSERT_MSG_EQ (m_sent, 300000, "Sent the full 300000 bytes");
+ NS_TEST_ASSERT_MSG_EQ (m_received, 300000, "Received the full 300000 bytes");
+}
+
+// This test checks that the sequence number is sent and received in sequence
+// despite the sending application having to pause and restart its sending
+// due to a temporarily full transmit buffer.
+class BulkSendSeqTsSizeTestCase : public TestCase
+{
+public:
+ BulkSendSeqTsSizeTestCase ();
+ virtual ~BulkSendSeqTsSizeTestCase ();
+
+private:
+ virtual void DoRun (void);
+ void SendTx (Ptr p, const Address &from, const Address & to, const SeqTsSizeHeader &header);
+ void ReceiveRx (Ptr p, const Address &from, const Address & to, const SeqTsSizeHeader &header);
+ uint64_t m_sent {0};
+ uint64_t m_received {0};
+ uint64_t m_seqTxCounter {0};
+ uint64_t m_seqRxCounter {0};
+ Time m_lastTxTs {Seconds (0)};
+ Time m_lastRxTs {Seconds (0)};
+};
+
+BulkSendSeqTsSizeTestCase::BulkSendSeqTsSizeTestCase ()
+ : TestCase ("Check a 300KB transfer with SeqTsSize header enabled")
+{
+}
+
+BulkSendSeqTsSizeTestCase::~BulkSendSeqTsSizeTestCase ()
+{
+}
+
+void
+BulkSendSeqTsSizeTestCase::SendTx (Ptr p, const Address &from, const Address & to, const SeqTsSizeHeader &header)
+{
+ // The header is not serialized onto the packet in this trace
+ m_sent += p->GetSize () + header.GetSerializedSize ();
+ NS_TEST_ASSERT_MSG_EQ (header.GetSeq (), m_seqTxCounter, "Missing sequence number");
+ m_seqTxCounter++;
+ NS_TEST_ASSERT_MSG_GT_OR_EQ (header.GetTs (), m_lastTxTs, "Timestamp less than last time");
+ m_lastTxTs = header.GetTs ();
+}
+
+void
+BulkSendSeqTsSizeTestCase::ReceiveRx (Ptr p, const Address &from, const Address & to, const SeqTsSizeHeader &header)
+{
+ // The header is not serialized onto the packet in this trace
+ m_received += p->GetSize () + header.GetSerializedSize ();
+ NS_TEST_ASSERT_MSG_EQ (header.GetSeq (), m_seqRxCounter, "Missing sequence number");
+ m_seqRxCounter++;
+ NS_TEST_ASSERT_MSG_GT_OR_EQ (header.GetTs (), m_lastRxTs, "Timestamp less than last time");
+ m_lastRxTs = header.GetTs ();
+}
+
+void
+BulkSendSeqTsSizeTestCase::DoRun (void)
+{
+ Ptr sender = CreateObject ();
+ Ptr receiver = CreateObject ();
+ NodeContainer nodes;
+ nodes.Add (sender);
+ nodes.Add (receiver);
+ PointToPointHelper p2pHelper;
+ p2pHelper.SetDeviceAttribute ("DataRate", StringValue ("10Mbps"));
+ p2pHelper.SetChannelAttribute ("Delay", StringValue ("10ms"));
+ NetDeviceContainer devices;
+ devices = p2pHelper.Install (nodes);
+ InternetStackHelper internet;
+ internet.Install (nodes);
+ Ipv4AddressHelper ipv4;
+ ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+ Ipv4InterfaceContainer i = ipv4.Assign (devices);
+ uint16_t port = 9;
+ BulkSendHelper sourceHelper ("ns3::TcpSocketFactory",
+ InetSocketAddress (i.GetAddress (1), port));
+ sourceHelper.SetAttribute ("MaxBytes", UintegerValue (300000));
+ sourceHelper.SetAttribute ("EnableSeqTsSizeHeader", BooleanValue (true));
+ ApplicationContainer sourceApp = sourceHelper.Install (nodes.Get (0));
+ sourceApp.Start (Seconds (0.0));
+ sourceApp.Stop (Seconds (10.0));
+ PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory",
+ InetSocketAddress (Ipv4Address::GetAny (), port));
+ sinkHelper.SetAttribute ("EnableSeqTsSizeHeader", BooleanValue (true));
+ ApplicationContainer sinkApp = sinkHelper.Install (nodes.Get (1));
+ sinkApp.Start (Seconds (0.0));
+ sinkApp.Stop (Seconds (10.0));
+
+ Ptr source = DynamicCast (sourceApp.Get (0));
+ Ptr sink = DynamicCast (sinkApp.Get (0));
+
+ source->TraceConnectWithoutContext ("TxWithSeqTsSize", MakeCallback (&BulkSendSeqTsSizeTestCase::SendTx, this));
+ sink->TraceConnectWithoutContext ("RxWithSeqTsSize", MakeCallback (&BulkSendSeqTsSizeTestCase::ReceiveRx, this));
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+
+ NS_TEST_ASSERT_MSG_EQ (m_sent, 300000, "Sent the full 300000 bytes");
+ NS_TEST_ASSERT_MSG_EQ (m_received, 300000, "Received the full 300000 bytes");
+}
+
+class BulkSendTestSuite : public TestSuite
+{
+public:
+ BulkSendTestSuite ();
+};
+
+BulkSendTestSuite::BulkSendTestSuite ()
+ : TestSuite ("bulk-send-application", UNIT)
+{
+ AddTestCase (new BulkSendBasicTestCase, TestCase::QUICK);
+ AddTestCase (new BulkSendSeqTsSizeTestCase, TestCase::QUICK);
+}
+
+static BulkSendTestSuite g_bulkSendTestSuite;
+
diff --git a/src/applications/wscript b/src/applications/wscript
index 64ebbc8c1..2ae4cf789 100644
--- a/src/applications/wscript
+++ b/src/applications/wscript
@@ -31,6 +31,7 @@ def build(bld):
applications_test = bld.create_ns3_module_test_library('applications')
applications_test.source = [
'test/three-gpp-http-client-server-test.cc',
+ 'test/bulk-send-application-test-suite.cc',
'test/udp-client-server-test.cc'
]