applications: Align E2eStatsHeader with other application headers (!211)

* E2eStatsHeader renamed to SeqTsSizeHeader, for module naming consistency
* BulkSendApplication::EnableE2EStats attribute renamed to EnableSeqTsSizeHeader
* BulkSendApplication::TxE2EStat trace source renamed to TxWithSeqTsSize
* OnOffApplication::EnableE2EStats attribute renamed to EnableSeqTsSizeHeader
* OnOffApplication::TxE2EStat trace source renamed to TxWithSeqTsSize
* PacketSink::EnableE2EStats attribute renamed to EnableSeqTsSizeHeader
* PacketSink::RxE2EStat trace source renamed to RxWithSeqTsSize
* Cache outgoing packet based on Socket::Send () failure (due to full buffer)
* Add test suite for BulkSendApplication, checking sequence number operation
* Various other review comments addressed, and doxygen alignments
This commit is contained in:
Tom Henderson
2020-03-10 10:56:25 -07:00
parent 5fd3f38528
commit c8f1267127
14 changed files with 435 additions and 154 deletions

View File

@@ -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.</li>
<li>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.</li>
<li> 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.</li>
<li>Added a new trace source <b>PhyRxPayloadBegin</b> in WifiPhy for tracing begin of PSDU reception.</li>
<li> 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.</li>
</ul>

View File

@@ -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> 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<Packet> (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)

View File

@@ -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<Packet> m_unsentPacket; //!< Variable to cache unsent packet
bool m_enableSeqTsSizeHeader {false}; //!< Enable or disable the SeqTsSizeHeader
/// Traced Callback: sent packets
TracedCallback<Ptr<const Packet> > m_txTrace;
/// Callback for tracing the packet Tx events, includes source, destination, and the packet sent
TracedCallback<Ptr<const Packet>, const Address &, const Address &, const E2eStatsHeader &> m_txTraceWithStats;
/// Callback for tracing the packet Tx events, includes source, destination, the packet sent, and header
TracedCallback<Ptr<const Packet>, const Address &, const Address &, const SeqTsSizeHeader &> m_txTraceWithSeqTsSize;
private:
/**

View File

@@ -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<double>(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> 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<Packet> (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<Packet> (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 ();
}

View File

@@ -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<Packet> 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<Ptr<const Packet>, const Address &, const Address &> m_txTraceWithAddresses;
/// Callback for tracing the packet Tx events, includes source, destination, and the packet sent
TracedCallback<Ptr<const Packet>, const Address &, const Address &, const E2eStatsHeader &> m_txTraceWithStats;
/// Callback for tracing the packet Tx events, includes source, destination, the packet sent, and header
TracedCallback<Ptr<const Packet>, const Address &, const Address &, const SeqTsSizeHeader &> m_txTraceWithSeqTsSize;
private:
/**

View File

@@ -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> 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<Packet> &p, const Address &from,
const Address &localAddress)
{
E2eStatsHeader header;
SeqTsSizeHeader header;
Ptr<Packet> buffer;
auto itBuffer = m_buffer.find (from);
@@ -236,14 +236,15 @@ PacketSink::PacketReceived (const Ptr<Packet> &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<Packet> complete = buffer->CreateFragment (0, static_cast<uint32_t> (header.GetSize ()));
buffer->RemoveAtStart (static_cast<uint32_t> (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<Packet> &p, const Address &from,
}
}
void PacketSink::HandlePeerClose (Ptr<Socket> socket)
{
NS_LOG_FUNCTION (this << socket);
@@ -264,7 +264,6 @@ void PacketSink::HandlePeerError (Ptr<Socket> socket)
{
NS_LOG_FUNCTION (this << socket);
}
void PacketSink::HandleAccept (Ptr<Socket> s, const Address& from)
{

View File

@@ -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 <unordered_map>
namespace ns3 {
@@ -96,16 +96,15 @@ public:
std::list<Ptr<Socket> > 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<const Packet> p, const Address &from, const Address & to,
const E2eStatsHeader &header);
typedef void (* SeqTsSizeCallback)(Ptr<const Packet> p, const Address &from, const Address & to,
const SeqTsSizeHeader &header);
protected:
virtual void DoDispose (void);
@@ -137,14 +136,13 @@ private:
void HandlePeerError (Ptr<Socket> 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<Packet> &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<Ptr<const Packet>, const Address &> m_rxTrace;
/// Callback for tracing the packet Rx events, includes source and destination addresses
TracedCallback<Ptr<const Packet>, const Address &, const Address &> m_rxTraceWithAddresses;
/// Callback for tracing the packet Rx events, includes source, destination addresses, sequence and timestamp
TracedCallback<Ptr<const Packet>, const Address &, const Address &, const E2eStatsHeader&> m_rxTraceWithAddressesAndSeqTs;
/// Callbacks for tracing the packet Rx events, includes source, destination addresses, and headers
TracedCallback<Ptr<const Packet>, const Address &, const Address &, const SeqTsSizeHeader&> m_rxTraceWithSeqTsSize;
};
} // namespace ns3

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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
{

View File

@@ -1,6 +1,8 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2009 INRIA
* Copyright (c) 2018 Natale Patriciello <natale.patriciello@gmail.com>
* (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<SeqTsHeader> ()
.SetGroupName ("Applications")
.AddConstructor<E2eStatsHeader> ()
.AddConstructor<SeqTsSizeHeader> ()
;
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;

View File

@@ -1,6 +1,8 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2009 INRIA
* Copyright (c) 2018 Natale Patriciello <natale.patriciello@gmail.com>
* (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 <ns3/seq-ts-header.h>
@@ -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 */

View File

@@ -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<const Packet> p);
void ReceiveRx (Ptr<const Packet> 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<const Packet> p)
{
m_sent += p->GetSize ();
}
void
BulkSendBasicTestCase::ReceiveRx (Ptr<const Packet> p, const Address& addr)
{
m_received += p->GetSize ();
}
void
BulkSendBasicTestCase::DoRun (void)
{
Ptr<Node> sender = CreateObject<Node> ();
Ptr<Node> receiver = CreateObject<Node> ();
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<BulkSendApplication> source = DynamicCast<BulkSendApplication> (sourceApp.Get (0));
Ptr<PacketSink> sink = DynamicCast<PacketSink> (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<const Packet> p, const Address &from, const Address & to, const SeqTsSizeHeader &header);
void ReceiveRx (Ptr<const Packet> 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<const Packet> 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<const Packet> 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<Node> sender = CreateObject<Node> ();
Ptr<Node> receiver = CreateObject<Node> ();
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<BulkSendApplication> source = DynamicCast<BulkSendApplication> (sourceApp.Get (0));
Ptr<PacketSink> sink = DynamicCast<PacketSink> (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;

View File

@@ -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'
]