diff --git a/CHANGES.html b/CHANGES.html
index 609d3082e..71d2eabbc 100644
--- a/CHANGES.html
+++ b/CHANGES.html
@@ -73,6 +73,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.
+The applications have now a "EnableE2EStats" attribute.
Changes to existing API:
diff --git a/src/applications/model/bulk-send-application.cc b/src/applications/model/bulk-send-application.cc
index 9b89ef2e3..44a463427 100644
--- a/src/applications/model/bulk-send-application.cc
+++ b/src/applications/model/bulk-send-application.cc
@@ -29,6 +29,7 @@
#include "ns3/uinteger.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/tcp-socket-factory.h"
+#include "ns3/boolean.h"
#include "bulk-send-application.h"
namespace ns3 {
@@ -52,6 +53,11 @@ BulkSendApplication::GetTypeId (void)
AddressValue (),
MakeAddressAccessor (&BulkSendApplication::m_peer),
MakeAddressChecker ())
+ .AddAttribute ("Local",
+ "The Address on which to bind the socket. If not set, it is generated automatically.",
+ AddressValue (),
+ MakeAddressAccessor (&BulkSendApplication::m_local),
+ MakeAddressChecker ())
.AddAttribute ("MaxBytes",
"The total number of bytes to send. "
"Once these bytes are sent, "
@@ -64,9 +70,17 @@ BulkSendApplication::GetTypeId (void)
TypeIdValue (TcpSocketFactory::GetTypeId ()),
MakeTypeIdAccessor (&BulkSendApplication::m_tid),
MakeTypeIdChecker ())
+ .AddAttribute ("EnableE2EStats",
+ "Enable E2E statistics (sequences, timestamps)",
+ BooleanValue (false),
+ MakeBooleanAccessor (&BulkSendApplication::m_enableE2EStats),
+ MakeBooleanChecker ())
.AddTraceSource ("Tx", "A new packet is created and is sent",
MakeTraceSourceAccessor (&BulkSendApplication::m_txTrace),
"ns3::Packet::TracedCallback")
+ .AddTraceSource ("TxE2EStat", "Statistic sent with the packet",
+ MakeTraceSourceAccessor (&BulkSendApplication::m_txTraceWithStats),
+ "ns3::PacketSink::E2EStatCallback")
;
return tid;
}
@@ -113,11 +127,13 @@ BulkSendApplication::DoDispose (void)
void BulkSendApplication::StartApplication (void) // Called at time specified by Start
{
NS_LOG_FUNCTION (this);
+ Address from;
// Create the socket if not already
if (!m_socket)
{
m_socket = Socket::CreateSocket (GetNode (), m_tid);
+ int ret = -1;
// Fatal error if socket type is not NS3_SOCK_STREAM or NS3_SOCK_SEQPACKET
if (m_socket->GetSocketType () != Socket::NS3_SOCK_STREAM &&
@@ -128,19 +144,28 @@ void BulkSendApplication::StartApplication (void) // Called at time specified by
"In other words, use TCP instead of UDP.");
}
- if (Inet6SocketAddress::IsMatchingType (m_peer))
+ if (! m_local.IsInvalid())
{
- if (m_socket->Bind6 () == -1)
+ NS_ABORT_MSG_IF ((Inet6SocketAddress::IsMatchingType (m_peer) && InetSocketAddress::IsMatchingType (m_local)) ||
+ (InetSocketAddress::IsMatchingType (m_peer) && Inet6SocketAddress::IsMatchingType (m_local)),
+ "Incompatible peer and local address IP version");
+ ret = m_socket->Bind (m_local);
+ }
+ else
+ {
+ if (Inet6SocketAddress::IsMatchingType (m_peer))
{
- NS_FATAL_ERROR ("Failed to bind socket");
+ ret = m_socket->Bind6 ();
+ }
+ else if (InetSocketAddress::IsMatchingType (m_peer))
+ {
+ ret = m_socket->Bind ();
}
}
- else if (InetSocketAddress::IsMatchingType (m_peer))
+
+ if (ret == -1)
{
- if (m_socket->Bind () == -1)
- {
- NS_FATAL_ERROR ("Failed to bind socket");
- }
+ NS_FATAL_ERROR ("Failed to bind socket");
}
m_socket->Connect (m_peer);
@@ -153,7 +178,8 @@ void BulkSendApplication::StartApplication (void) // Called at time specified by
}
if (m_connected)
{
- SendData ();
+ m_socket->GetSockName (from);
+ SendData (from, m_peer);
}
}
@@ -175,7 +201,7 @@ void BulkSendApplication::StopApplication (void) // Called at time specified by
// Private helpers
-void BulkSendApplication::SendData (void)
+void BulkSendApplication::SendData (const Address &from, const Address &to)
{
NS_LOG_FUNCTION (this);
@@ -193,7 +219,24 @@ void BulkSendApplication::SendData (void)
}
NS_LOG_LOGIC ("sending packet at " << Simulator::Now ());
- Ptr packet = Create (toSend);
+
+ Ptr packet;
+ if (m_enableE2EStats)
+ {
+ // Should we add a trace for the sent tx and timestamp?
+ E2eStatsHeader header;
+ header.SetSeq (m_seq++);
+ header.SetSize (toSend);
+ NS_ABORT_IF (toSend < header.GetSerializedSize ());
+ packet = Create (toSend - header.GetSerializedSize ());
+ packet->AddHeader (header);
+ m_txTraceWithStats (packet, from, to, header);
+ }
+ else
+ {
+ packet = Create (toSend);
+ }
+
int actual = m_socket->Send (packet);
if (actual > 0)
{
@@ -221,7 +264,10 @@ void BulkSendApplication::ConnectionSucceeded (Ptr socket)
NS_LOG_FUNCTION (this << socket);
NS_LOG_LOGIC ("BulkSendApplication Connection succeeded");
m_connected = true;
- SendData ();
+ Address from, to;
+ socket->GetSockName (from);
+ socket->GetPeerName (to);
+ SendData (from, to);
}
void BulkSendApplication::ConnectionFailed (Ptr socket)
@@ -230,13 +276,16 @@ void BulkSendApplication::ConnectionFailed (Ptr socket)
NS_LOG_LOGIC ("BulkSendApplication, Connection Failed");
}
-void BulkSendApplication::DataSend (Ptr, uint32_t)
+void BulkSendApplication::DataSend (Ptr socket, uint32_t)
{
NS_LOG_FUNCTION (this);
if (m_connected)
{ // Only send new data if the connection has completed
- SendData ();
+ Address from, to;
+ socket->GetSockName (from);
+ socket->GetPeerName (to);
+ SendData (from, to);
}
}
diff --git a/src/applications/model/bulk-send-application.h b/src/applications/model/bulk-send-application.h
index d1121a1c2..544ef8414 100644
--- a/src/applications/model/bulk-send-application.h
+++ b/src/applications/model/bulk-send-application.h
@@ -26,6 +26,7 @@
#include "ns3/event-id.h"
#include "ns3/ptr.h"
#include "ns3/traced-callback.h"
+#include "ns3/e2e-stats-header.h"
namespace ns3 {
@@ -64,6 +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).
*/
class BulkSendApplication : public Application
{
@@ -108,20 +115,29 @@ private:
/**
* \brief Send data until the L4 transmission buffer is full.
+ * \param from From address
+ * \param to To address
*/
- void SendData ();
+ void SendData (const Address &from, const Address &to);
Ptr m_socket; //!< Associated socket
Address m_peer; //!< Peer address
+ Address m_local; //!< Local address to bind to
bool m_connected; //!< True if connected
uint32_t m_sendSize; //!< Size of data to send each time
uint64_t m_maxBytes; //!< Limit total number of bytes sent
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
+
/// 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;
+
private:
/**
* \brief Connection Succeeded (called by Socket through a callback)
diff --git a/src/applications/model/e2e-stats-header.cc b/src/applications/model/e2e-stats-header.cc
new file mode 100644
index 000000000..753b84d54
--- /dev/null
+++ b/src/applications/model/e2e-stats-header.cc
@@ -0,0 +1,86 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2018 Natale Patriciello
+ *
+ * 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/log.h"
+#include "e2e-stats-header.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("SizeHeader");
+
+NS_OBJECT_ENSURE_REGISTERED (E2eStatsHeader);
+
+E2eStatsHeader::E2eStatsHeader ()
+ : SeqTsHeader ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+TypeId
+E2eStatsHeader::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::SizeHeader")
+ .SetParent ()
+ .SetGroupName ("Applications")
+ .AddConstructor ()
+ ;
+ return tid;
+}
+
+TypeId
+E2eStatsHeader::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+void
+E2eStatsHeader::Print (std::ostream &os) const
+{
+ NS_LOG_FUNCTION (this << &os);
+ os << "(size=" << m_size << ") AND ";
+ SeqTsHeader::Print (os);
+}
+
+uint32_t
+E2eStatsHeader::GetSerializedSize (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return SeqTsHeader::GetSerializedSize () + 8;
+}
+
+void
+E2eStatsHeader::Serialize (Buffer::Iterator start) const
+{
+ NS_LOG_FUNCTION (this << &start);
+ Buffer::Iterator i = start;
+ i.WriteHtonU64 (m_size);
+ SeqTsHeader::Serialize (i);
+}
+
+uint32_t
+E2eStatsHeader::Deserialize (Buffer::Iterator start)
+{
+ NS_LOG_FUNCTION (this << &start);
+ Buffer::Iterator i = start;
+ m_size = i.ReadNtohU64 ();
+ SeqTsHeader::Deserialize (i);
+ return GetSerializedSize ();
+}
+
+} // namespace ns3
diff --git a/src/applications/model/e2e-stats-header.h b/src/applications/model/e2e-stats-header.h
new file mode 100644
index 000000000..f3bdfeb6d
--- /dev/null
+++ b/src/applications/model/e2e-stats-header.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2018 Natale Patriciello
+ *
+ * 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
+ */
+
+#pragma once
+
+#include
+
+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 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?".
+ */
+class E2eStatsHeader : public SeqTsHeader
+{
+public:
+ /**
+ * \brief Get the type ID.
+ * \return the object TypeId
+ */
+ static TypeId GetTypeId (void);
+
+ /**
+ * @brief SizeHeader constructor
+ */
+ E2eStatsHeader ();
+
+ /**
+ * \brief ~SizeHeader
+ *
+ * Nothing much to add here
+ */
+ virtual ~E2eStatsHeader () override
+ {
+ }
+
+ /**
+ * @brief Set the size information that the header will carry
+ * @param size 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;
+ }
+
+ // Inherited
+ virtual TypeId GetInstanceTypeId (void) const override;
+ virtual void Print (std::ostream &os) const override;
+ virtual uint32_t GetSerializedSize (void) const override;
+ virtual void Serialize (Buffer::Iterator start) const override;
+ virtual uint32_t Deserialize (Buffer::Iterator start) override;
+
+private:
+ uint64_t m_size {0}; //!< The 'size' information that the header is carrying
+};
+
+} // namespace ns3
diff --git a/src/applications/model/onoff-application.cc b/src/applications/model/onoff-application.cc
index 76d6c58a0..166612e61 100644
--- a/src/applications/model/onoff-application.cc
+++ b/src/applications/model/onoff-application.cc
@@ -41,6 +41,7 @@
#include "ns3/udp-socket-factory.h"
#include "ns3/string.h"
#include "ns3/pointer.h"
+#include "ns3/boolean.h"
namespace ns3 {
@@ -67,6 +68,11 @@ OnOffApplication::GetTypeId (void)
AddressValue (),
MakeAddressAccessor (&OnOffApplication::m_peer),
MakeAddressChecker ())
+ .AddAttribute ("Local",
+ "The Address on which to bind the socket. If not set, it is generated automatically.",
+ AddressValue (),
+ MakeAddressAccessor (&OnOffApplication::m_local),
+ MakeAddressChecker ())
.AddAttribute ("OnTime", "A RandomVariableStream used to pick the duration of the 'On' state.",
StringValue ("ns3::ConstantRandomVariable[Constant=1.0]"),
MakePointerAccessor (&OnOffApplication::m_onTime),
@@ -88,12 +94,20 @@ OnOffApplication::GetTypeId (void)
MakeTypeIdAccessor (&OnOffApplication::m_tid),
// This should check for SocketFactory as a parent
MakeTypeIdChecker ())
+ .AddAttribute ("EnableE2EStats",
+ "Enable E2E statistics (sequences, timestamps)",
+ BooleanValue (false),
+ MakeBooleanAccessor (&OnOffApplication::m_enableE2EStats),
+ MakeBooleanChecker ())
.AddTraceSource ("Tx", "A new packet is created and is sent",
MakeTraceSourceAccessor (&OnOffApplication::m_txTrace),
"ns3::Packet::TracedCallback")
.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")
;
return tid;
}
@@ -157,21 +171,33 @@ void OnOffApplication::StartApplication () // Called at time specified by Start
if (!m_socket)
{
m_socket = Socket::CreateSocket (GetNode (), m_tid);
- if (Inet6SocketAddress::IsMatchingType (m_peer))
+ int ret = -1;
+
+ if (! m_local.IsInvalid())
{
- if (m_socket->Bind6 () == -1)
+ NS_ABORT_MSG_IF ((Inet6SocketAddress::IsMatchingType (m_peer) && InetSocketAddress::IsMatchingType (m_local)) ||
+ (InetSocketAddress::IsMatchingType (m_peer) && Inet6SocketAddress::IsMatchingType (m_local)),
+ "Incompatible peer and local address IP version");
+ ret = m_socket->Bind (m_local);
+ }
+ else
+ {
+ if (Inet6SocketAddress::IsMatchingType (m_peer))
{
- NS_FATAL_ERROR ("Failed to bind socket");
+ ret = m_socket->Bind6 ();
+ }
+ else if (InetSocketAddress::IsMatchingType (m_peer) ||
+ PacketSocketAddress::IsMatchingType (m_peer))
+ {
+ ret = m_socket->Bind ();
}
}
- else if (InetSocketAddress::IsMatchingType (m_peer) ||
- PacketSocketAddress::IsMatchingType (m_peer))
+
+ if (ret == -1)
{
- if (m_socket->Bind () == -1)
- {
- NS_FATAL_ERROR ("Failed to bind socket");
- }
+ NS_FATAL_ERROR ("Failed to bind socket");
}
+
m_socket->Connect (m_peer);
m_socket->SetAllowBroadcast (true);
m_socket->ShutdownRecv ();
@@ -283,7 +309,26 @@ void OnOffApplication::SendPacket ()
NS_LOG_FUNCTION (this);
NS_ASSERT (m_sendEvent.IsExpired ());
- Ptr packet = Create (m_pktSize);
+
+ Ptr packet;
+ if (m_enableE2EStats)
+ {
+ Address from, to;
+ m_socket->GetSockName (from);
+ m_socket->GetPeerName (to);
+ E2eStatsHeader header;
+ header.SetSeq (m_seq++);
+ header.SetSize (m_pktSize);
+ NS_ABORT_IF (m_pktSize < header.GetSerializedSize ());
+ packet = Create (m_pktSize - header.GetSerializedSize ());
+ 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;
@@ -324,6 +369,7 @@ void OnOffApplication::ConnectionSucceeded (Ptr socket)
void OnOffApplication::ConnectionFailed (Ptr socket)
{
NS_LOG_FUNCTION (this << socket);
+ NS_FATAL_ERROR ("Can't connect");
}
diff --git a/src/applications/model/onoff-application.h b/src/applications/model/onoff-application.h
index 6b075c916..90711c1a0 100644
--- a/src/applications/model/onoff-application.h
+++ b/src/applications/model/onoff-application.h
@@ -31,6 +31,7 @@
#include "ns3/ptr.h"
#include "ns3/data-rate.h"
#include "ns3/traced-callback.h"
+#include "ns3/e2e-stats-header.h"
namespace ns3 {
@@ -82,6 +83,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).
*/
class OnOffApplication : public Application
{
@@ -150,6 +158,7 @@ private:
Ptr m_socket; //!< Associated socket
Address m_peer; //!< Peer address
+ Address m_local; //!< Local address to bind to
bool m_connected; //!< True if connected
Ptr m_onTime; //!< rng for On Time
Ptr m_offTime; //!< rng for Off Time
@@ -163,6 +172,9 @@ private:
EventId m_startStopEvent; //!< Event id for next start or stop event
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
+
/// Traced Callback: transmitted packets.
TracedCallback > m_txTrace;
@@ -170,6 +182,9 @@ 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;
+
private:
/**
* \brief Schedule the next packet transmission
diff --git a/src/applications/model/packet-sink.cc b/src/applications/model/packet-sink.cc
index 832af588d..16c539834 100644
--- a/src/applications/model/packet-sink.cc
+++ b/src/applications/model/packet-sink.cc
@@ -31,6 +31,7 @@
#include "ns3/trace-source-accessor.h"
#include "ns3/udp-socket-factory.h"
#include "packet-sink.h"
+#include "ns3/boolean.h"
namespace ns3 {
@@ -55,6 +56,11 @@ PacketSink::GetTypeId (void)
TypeIdValue (UdpSocketFactory::GetTypeId ()),
MakeTypeIdAccessor (&PacketSink::m_tid),
MakeTypeIdChecker ())
+ .AddAttribute ("EnableE2EStats",
+ "Enable E2E statistics (sequences, timestamps)",
+ BooleanValue (false),
+ MakeBooleanAccessor (&PacketSink::m_enableE2EStats),
+ MakeBooleanChecker ())
.AddTraceSource ("Rx",
"A packet has been received",
MakeTraceSourceAccessor (&PacketSink::m_rxTrace),
@@ -62,6 +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")
;
return tid;
}
@@ -197,6 +207,50 @@ void PacketSink::HandleRead (Ptr socket)
socket->GetSockName (localAddress);
m_rxTrace (packet, from);
m_rxTraceWithAddresses (packet, from, localAddress);
+
+ if (m_enableE2EStats)
+ {
+ PacketReceived (packet, from, localAddress);
+ }
+ }
+}
+
+void
+PacketSink::PacketReceived (const Ptr &p, const Address &from,
+ const Address &localAddress)
+{
+ E2eStatsHeader header;
+ Ptr buffer;
+
+ auto itBuffer = m_buffer.find (from);
+ if (itBuffer == m_buffer.end ())
+ {
+ itBuffer = m_buffer.insert (std::make_pair (from, Create (0))).first;
+ }
+
+ buffer = itBuffer->second;
+ buffer->AddAtEnd (p);
+ buffer->PeekHeader (header);
+
+ NS_ABORT_IF (header.GetSize () == 0);
+
+ while (buffer->GetSize () >= header.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);
+
+ if (buffer->GetSize () > 0)
+ {
+ buffer->PeekHeader (header);
+ }
+ else
+ {
+ break;
+ }
}
}
diff --git a/src/applications/model/packet-sink.h b/src/applications/model/packet-sink.h
index d54ef5d91..b583bcdaa 100644
--- a/src/applications/model/packet-sink.h
+++ b/src/applications/model/packet-sink.h
@@ -26,6 +26,9 @@
#include "ns3/ptr.h"
#include "ns3/traced-callback.h"
#include "ns3/address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/e2e-stats-header.h"
+#include
namespace ns3 {
@@ -91,7 +94,19 @@ public:
* \return list of pointers to accepted sockets
*/
std::list > GetAcceptedSockets (void) const;
-
+
+ /**
+ * TracedCallback signature for an E2E stat callback
+ *
+ * \param p The packet received
+ * \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
+ */
+ typedef void (* E2EStatCallback)(Ptr p, const Address &from, const Address & to,
+ const E2eStatsHeader &header);
+
protected:
virtual void DoDispose (void);
private:
@@ -121,7 +136,44 @@ private:
*/
void HandlePeerError (Ptr socket);
- // In the case of TCP, each socket accept returns a new socket, so the
+ /**
+ * \brief Packet received: calculation of the e2e statistics
+ * \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.
+ */
+ void PacketReceived (const Ptr &p, const Address &from, const Address &localAddress);
+
+ /**
+ * \brief Hashing for the Address class
+ */
+ struct AddressHash
+ {
+ /**
+ * \brief operator ()
+ * \param x the address of which calculate the hash
+ * \return the hash of x
+ *
+ * Should this method go in address.h?
+ *
+ * It calculates the hash taking the uint32_t hash value of the ipv4 address.
+ * It works only for InetSocketAddresses (Ipv4 version)
+ */
+ size_t operator() (const Address &x) const
+ {
+ NS_ABORT_IF (!InetSocketAddress::IsMatchingType (x));
+ InetSocketAddress a = InetSocketAddress::ConvertFrom (x);
+ return std::hash()(a.GetIpv4 ().Get ());
+ }
+ };
+
+ std::unordered_map, AddressHash> m_buffer; //!< Buffer for received packets
+
+ // In the case of TCP, each socket accept returns a new socket, so the
// listening socket is stored separately from the accepted sockets
Ptr m_socket; //!< Listening socket
std::list > m_socketList; //!< the accepted sockets
@@ -130,12 +182,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
+
/// 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;
};
} // namespace ns3
diff --git a/src/applications/model/seq-ts-header.h b/src/applications/model/seq-ts-header.h
index 3bc40a300..add229d37 100644
--- a/src/applications/model/seq-ts-header.h
+++ b/src/applications/model/seq-ts-header.h
@@ -31,7 +31,8 @@ namespace ns3 {
* \brief Packet header for UDP client/server application.
*
* The header is made of a 32bits sequence number followed by
- * a 64bits time stamp.
+ * a 64bits time stamp. If you need to use this header with a transport protocol
+ * such as TCP, please consider to use SizeHeader.
*/
class SeqTsHeader : public Header
{
diff --git a/src/applications/wscript b/src/applications/wscript
index 453961a46..97edfd47c 100644
--- a/src/applications/wscript
+++ b/src/applications/wscript
@@ -9,6 +9,7 @@ def build(bld):
'model/udp-client.cc',
'model/udp-server.cc',
'model/seq-ts-header.cc',
+ 'model/e2e-stats-header.cc',
'model/udp-trace-client.cc',
'model/packet-loss-counter.cc',
'model/udp-echo-client.cc',
@@ -41,6 +42,7 @@ def build(bld):
'model/udp-client.h',
'model/udp-server.h',
'model/seq-ts-header.h',
+ 'model/e2e-stats-header.h',
'model/udp-trace-client.h',
'model/packet-loss-counter.h',
'model/udp-echo-client.h',