Added a GeneralTest class for TCP
The class provides a general infrastructure for a TCP-related test, setting up the environment (two sockets connected through SimpleNetDevice over SimpleChannel) and provides the basic management of parameters (like segment size).
This commit is contained in:
@@ -245,6 +245,9 @@ public:
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
friend class TcpGeneralTest;
|
||||
|
||||
/**
|
||||
* Create an unbound TCP socket
|
||||
*/
|
||||
@@ -559,7 +562,7 @@ protected:
|
||||
*
|
||||
* \param flags the packet's flags
|
||||
*/
|
||||
void SendEmptyPacket (uint8_t flags);
|
||||
virtual void SendEmptyPacket (uint8_t flags);
|
||||
|
||||
/**
|
||||
* \brief Send reset and tear down this socket
|
||||
|
||||
884
src/internet/test/tcp-general-test.cc
Normal file
884
src/internet/test/tcp-general-test.cc
Normal file
@@ -0,0 +1,884 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2015 Natale Patriciello <natale.patriciello@gmail.com>
|
||||
*
|
||||
* 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/node-container.h"
|
||||
#include "ns3/tcp-socket-base.h"
|
||||
#include "ns3/simple-net-device-helper.h"
|
||||
#include "ns3/ipv4-address-helper.h"
|
||||
#include "ns3/internet-stack-helper.h"
|
||||
#include "ns3/log.h"
|
||||
#include "tcp-general-test.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpGeneralTest");
|
||||
|
||||
TcpGeneralTest::TcpGeneralTest (const std::string &desc,
|
||||
uint32_t pktSize, uint32_t pktCount,
|
||||
const Time& pktInterval,
|
||||
const Time& propagationDelay, const Time& startTime,
|
||||
uint32_t initialSlowStartThresh, uint32_t initialCwnd,
|
||||
uint32_t segmentSize,
|
||||
TypeId congestionControl,
|
||||
uint32_t mtu)
|
||||
: TestCase (desc),
|
||||
m_congControlTypeId (congestionControl),
|
||||
m_propagationDelay (propagationDelay),
|
||||
m_startTime (startTime),
|
||||
m_mtu (mtu),
|
||||
m_pktSize (pktSize),
|
||||
m_pktCount (pktCount),
|
||||
m_interPacketInterval (pktInterval),
|
||||
m_initialSlowStartThresh (initialSlowStartThresh),
|
||||
m_initialCwnd (initialCwnd),
|
||||
m_segmentSize (segmentSize)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << desc);
|
||||
}
|
||||
|
||||
TcpGeneralTest::~TcpGeneralTest ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::ReceivePacket (Ptr<Socket> socket)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << socket);
|
||||
Ptr<Packet> packet;
|
||||
Address from;
|
||||
|
||||
while ((packet = socket->RecvFrom (from)))
|
||||
{
|
||||
if (packet->GetSize () == 0)
|
||||
{ //EOF
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::SendPacket (Ptr<Socket> socket, uint32_t pktSize,
|
||||
uint32_t pktCount, Time pktInterval )
|
||||
{
|
||||
NS_LOG_FUNCTION (this << " " << pktSize << " " << pktCount << " " <<
|
||||
pktInterval.GetSeconds ());
|
||||
if (pktCount > 0)
|
||||
{
|
||||
socket->Send (Create<Packet> (pktSize));
|
||||
Simulator::Schedule (pktInterval, &TcpGeneralTest::SendPacket, this,
|
||||
socket, pktSize, pktCount - 1, pktInterval);
|
||||
}
|
||||
else
|
||||
{
|
||||
socket->Close ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::DoTeardown (void)
|
||||
{
|
||||
FinalChecks ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::DoRun (void)
|
||||
{
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer nodes;
|
||||
nodes.Create (2);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (nodes);
|
||||
|
||||
Packet::EnablePrinting ();
|
||||
|
||||
Ptr<SimpleChannel> channel = CreateChannel ();
|
||||
|
||||
SimpleNetDeviceHelper helperChannel;
|
||||
helperChannel.SetNetDevicePointToPointMode (true);
|
||||
|
||||
NetDeviceContainer net = helperChannel.Install (nodes, channel);
|
||||
|
||||
Ptr<ErrorModel> receiverEM = CreateReceiverErrorModel ();
|
||||
Ptr<ErrorModel> senderEM = CreateSenderErrorModel ();
|
||||
|
||||
Ptr<SimpleNetDevice> senderDev = DynamicCast<SimpleNetDevice> (net.Get (0));
|
||||
Ptr<SimpleNetDevice> receiverDev = DynamicCast<SimpleNetDevice> (net.Get (1));
|
||||
|
||||
senderDev->SetMtu (m_mtu);
|
||||
senderDev->GetQueue ()->TraceConnect ("Drop", "SENDER",
|
||||
MakeCallback (&TcpGeneralTest::QueueDropCb, this));
|
||||
senderDev->TraceConnect ("PhyRxDrop", "sender",
|
||||
MakeCallback (&TcpGeneralTest::PhyDropCb, this));
|
||||
|
||||
receiverDev->SetMtu (m_mtu);
|
||||
receiverDev->GetQueue ()->TraceConnect ("Drop", "RECEIVER",
|
||||
MakeCallback (&TcpGeneralTest::QueueDropCb, this));
|
||||
receiverDev->TraceConnect ("PhyRxDrop", "RECEIVER",
|
||||
MakeCallback (&TcpGeneralTest::PhyDropCb, this));
|
||||
|
||||
senderDev->SetReceiveErrorModel (senderEM);
|
||||
receiverDev->SetReceiveErrorModel (receiverEM);
|
||||
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i = ipv4.Assign (net);
|
||||
Ipv4Address serverAddress = i.GetAddress (1);
|
||||
//Ipv4Address clientAddress = i.GetAddress (0);
|
||||
|
||||
NS_LOG_INFO ("Create sockets.");
|
||||
//Receiver socket on n1
|
||||
m_receiverSocket = CreateReceiverSocket (nodes.Get (1));
|
||||
|
||||
m_receiverSocket->SetRecvCallback (MakeCallback (&TcpGeneralTest::ReceivePacket, this));
|
||||
m_receiverSocket->SetAcceptCallback (
|
||||
MakeNullCallback<bool, Ptr<Socket>, const Address &> (),
|
||||
MakeCallback (&TcpGeneralTest::HandleAccept, this));
|
||||
m_receiverSocket->SetCloseCallbacks (MakeCallback (&TcpGeneralTest::NormalCloseCb, this),
|
||||
MakeCallback (&TcpGeneralTest::ErrorCloseCb, this));
|
||||
m_receiverSocket->SetRcvAckCb (MakeCallback (&TcpGeneralTest::RcvAckCb, this));
|
||||
m_receiverSocket->SetProcessedAckCb (MakeCallback (&TcpGeneralTest::ProcessedAckCb, this));
|
||||
m_receiverSocket->SetRetransmitCb (MakeCallback (&TcpGeneralTest::RtoExpiredCb, this));
|
||||
m_receiverSocket->SetForkCb (MakeCallback (&TcpGeneralTest::ForkCb, this));
|
||||
m_receiverSocket->TraceConnectWithoutContext ("Tx",
|
||||
MakeCallback (&TcpGeneralTest::TxPacketCb, this));
|
||||
m_receiverSocket->TraceConnectWithoutContext ("Rx",
|
||||
MakeCallback (&TcpGeneralTest::RxPacketCb, this));
|
||||
|
||||
InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 4477);
|
||||
m_receiverSocket->Bind (local);
|
||||
m_receiverSocket->Listen ();
|
||||
m_receiverSocket->ShutdownSend ();
|
||||
|
||||
m_senderSocket = CreateSenderSocket (nodes.Get (0));
|
||||
m_senderSocket->SetCloseCallbacks (MakeCallback (&TcpGeneralTest::NormalCloseCb, this),
|
||||
MakeCallback (&TcpGeneralTest::ErrorCloseCb, this));
|
||||
m_senderSocket->SetRcvAckCb (MakeCallback (&TcpGeneralTest::RcvAckCb, this));
|
||||
m_senderSocket->SetProcessedAckCb (MakeCallback (&TcpGeneralTest::ProcessedAckCb, this));
|
||||
m_senderSocket->SetRetransmitCb (MakeCallback (&TcpGeneralTest::RtoExpiredCb, this));
|
||||
m_senderSocket->TraceConnectWithoutContext ("CongestionWindow",
|
||||
MakeCallback (&TcpGeneralTest::CWndTrace, this));
|
||||
m_senderSocket->TraceConnectWithoutContext ("AckState",
|
||||
MakeCallback (&TcpGeneralTest::AckStateTrace, this));
|
||||
m_senderSocket->TraceConnectWithoutContext ("Tx",
|
||||
MakeCallback (&TcpGeneralTest::TxPacketCb, this));
|
||||
m_senderSocket->TraceConnectWithoutContext ("Rx",
|
||||
MakeCallback (&TcpGeneralTest::RxPacketCb, this));
|
||||
|
||||
InetSocketAddress remoteAddr = InetSocketAddress (serverAddress, 4477);
|
||||
|
||||
m_senderSocket->Connect (remoteAddr);
|
||||
|
||||
Simulator::ScheduleWithContext (nodes.Get (0)->GetId (),
|
||||
m_startTime, &TcpGeneralTest::SendPacket, this,
|
||||
m_senderSocket, m_pktSize, m_pktCount, m_interPacketInterval);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::HandleAccept (Ptr<Socket> socket, const Address& from)
|
||||
{
|
||||
(void) from;
|
||||
socket->SetRecvCallback (MakeCallback (&TcpGeneralTest::ReceivePacket, this));
|
||||
socket->SetCloseCallbacks (MakeCallback (&TcpGeneralTest::NormalCloseCb, this),
|
||||
MakeCallback (&TcpGeneralTest::ErrorCloseCb, this));
|
||||
|
||||
}
|
||||
|
||||
Ptr<SimpleChannel>
|
||||
TcpGeneralTest::CreateChannel ()
|
||||
{
|
||||
Ptr<SimpleChannel> ch = CreateObject <SimpleChannel> ();
|
||||
|
||||
ch->SetAttribute ("Delay", TimeValue (m_propagationDelay));
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
Ptr<TcpSocketMsgBase>
|
||||
TcpGeneralTest::CreateSocket (Ptr<Node> node, TypeId socketType,
|
||||
TypeId congControl)
|
||||
{
|
||||
ObjectFactory rttFactory;
|
||||
ObjectFactory congestionAlgorithmFactory;
|
||||
ObjectFactory socketFactory;
|
||||
|
||||
rttFactory.SetTypeId (RttMeanDeviation::GetTypeId ());
|
||||
congestionAlgorithmFactory.SetTypeId (congControl);
|
||||
socketFactory.SetTypeId (socketType);
|
||||
|
||||
Ptr<RttEstimator> rtt = rttFactory.Create<RttEstimator> ();
|
||||
Ptr<TcpSocketMsgBase> socket = socketFactory.Create <TcpSocketMsgBase> ();
|
||||
Ptr<TcpCongestionOps> algo = congestionAlgorithmFactory.Create<TcpCongestionOps> ();
|
||||
|
||||
socket->SetNode (node);
|
||||
socket->SetTcp (node->GetObject<TcpL4Protocol> ());
|
||||
socket->SetRtt (rtt);
|
||||
socket->SetCongestionControlAlgorithm (algo);
|
||||
|
||||
socket->SetAttribute ("InitialSlowStartThreshold", UintegerValue (m_initialSlowStartThresh));
|
||||
socket->SetAttribute ("SegmentSize", UintegerValue (m_segmentSize));
|
||||
socket->SetAttribute ("InitialCwnd", UintegerValue (m_initialCwnd));
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
Ptr<ErrorModel>
|
||||
TcpGeneralTest::CreateSenderErrorModel ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ptr<ErrorModel>
|
||||
TcpGeneralTest::CreateReceiverErrorModel ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ptr<TcpSocketMsgBase>
|
||||
TcpGeneralTest::CreateSenderSocket (Ptr<Node> node)
|
||||
{
|
||||
return CreateSocket (node, TcpSocketMsgBase::GetTypeId (), m_congControlTypeId);
|
||||
}
|
||||
|
||||
Ptr<TcpSocketMsgBase>
|
||||
TcpGeneralTest::CreateReceiverSocket (Ptr<Node> node)
|
||||
{
|
||||
return CreateSocket (node, TcpSocketMsgBase::GetTypeId (), m_congControlTypeId);
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::QueueDropCb ( std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
if (context.compare ("SENDER") == 0)
|
||||
{
|
||||
QueueDrop (SENDER);
|
||||
}
|
||||
else if (context.compare ("RECEIVER") == 0)
|
||||
{
|
||||
QueueDrop (RECEIVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Packet dropped in a queue, but queue not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::PhyDropCb (std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
if (context.compare ("SENDER") == 0)
|
||||
{
|
||||
PhyDrop (SENDER);
|
||||
}
|
||||
else if (context.compare ("RECEIVER") == 0)
|
||||
{
|
||||
PhyDrop (RECEIVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Packet dropped in a queue, but queue not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::NormalCloseCb (Ptr<Socket> socket)
|
||||
{
|
||||
if (socket->GetNode () == m_receiverSocket->GetNode ())
|
||||
{
|
||||
NormalClose (RECEIVER);
|
||||
}
|
||||
else if (socket->GetNode () == m_senderSocket->GetNode ())
|
||||
{
|
||||
NormalClose (SENDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Closed socket, but not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::RtoExpiredCb (const Ptr<const TcpSocketState> tcb,
|
||||
const Ptr<const TcpSocketBase> tcp)
|
||||
{
|
||||
if (tcp->GetNode () == m_receiverSocket->GetNode ())
|
||||
{
|
||||
RTOExpired (tcb, RECEIVER);
|
||||
}
|
||||
else if (tcp->GetNode () == m_senderSocket->GetNode ())
|
||||
{
|
||||
RTOExpired (tcb, SENDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Closed socket, but not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::ErrorCloseCb (Ptr<Socket> socket)
|
||||
{
|
||||
if (socket->GetNode () == m_receiverSocket->GetNode ())
|
||||
{
|
||||
ErrorClose (RECEIVER);
|
||||
}
|
||||
else if (socket->GetNode () == m_senderSocket->GetNode ())
|
||||
{
|
||||
ErrorClose (SENDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Closed socket, but not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::RcvAckCb (const Ptr<const Packet> p, const TcpHeader& h,
|
||||
const Ptr<const TcpSocketBase> tcp)
|
||||
{
|
||||
if (tcp->GetNode () == m_receiverSocket->GetNode ())
|
||||
{
|
||||
RcvAck (tcp->m_tcb, h, RECEIVER);
|
||||
}
|
||||
else if (tcp->GetNode () == m_senderSocket->GetNode ())
|
||||
{
|
||||
RcvAck (tcp->m_tcb, h, SENDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Received ACK but socket not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::TxPacketCb (const Ptr<const Packet> p,
|
||||
const TcpHeader &h, const Ptr<const TcpSocketBase> tcp)
|
||||
{
|
||||
if (tcp->GetNode () == m_receiverSocket->GetNode ())
|
||||
{
|
||||
Tx (p, h, RECEIVER);
|
||||
}
|
||||
else if (tcp->GetNode () == m_senderSocket->GetNode ())
|
||||
{
|
||||
Tx (p, h, SENDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Received ACK but socket not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::RxPacketCb (const Ptr<const Packet> p, const TcpHeader &h,
|
||||
const Ptr<const TcpSocketBase> tcp)
|
||||
{
|
||||
if (tcp->GetNode () == m_receiverSocket->GetNode ())
|
||||
{
|
||||
Rx (p, h, RECEIVER);
|
||||
}
|
||||
else if (tcp->GetNode () == m_senderSocket->GetNode ())
|
||||
{
|
||||
Rx (p, h, SENDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Received ACK but socket not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::ProcessedAckCb (Ptr<const Packet> p, const TcpHeader& h,
|
||||
Ptr<const TcpSocketBase> tcp)
|
||||
{
|
||||
if (tcp->GetNode () == m_receiverSocket->GetNode ())
|
||||
{
|
||||
ProcessedAck (tcp->m_tcb, h, RECEIVER);
|
||||
}
|
||||
else if (tcp->GetNode () == m_senderSocket->GetNode ())
|
||||
{
|
||||
ProcessedAck (tcp->m_tcb, h, SENDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Received ACK but socket not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::ForkCb (Ptr<TcpSocketMsgBase> tcp)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << tcp);
|
||||
|
||||
m_receiverSocket = tcp;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpGeneralTest::GetReTxThreshold (SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->m_retxThresh;
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->m_retxThresh;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpGeneralTest::GetDupAckCount (SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->m_dupAckCount;
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->m_dupAckCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpGeneralTest::GetDelAckCount (SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->m_delAckMaxCount;
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->m_delAckMaxCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
Time
|
||||
TcpGeneralTest::GetDelAckTimeout(SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->GetDelAckTimeout ();
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->GetDelAckTimeout ();
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpGeneralTest::GetSegSize (SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->GetSegSize ();
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->GetSegSize ();
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
Time
|
||||
TcpGeneralTest::GetRto (SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->m_rto.Get ();
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->m_rto.Get ();
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
Time
|
||||
TcpGeneralTest::GetMinRto (SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->m_minRto;
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->m_minRto;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
Time
|
||||
TcpGeneralTest::GetConnTimeout (SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->m_cnTimeout;
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->m_cnTimeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<RttEstimator>
|
||||
TcpGeneralTest::GetRttEstimator (SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->m_rtt;
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->m_rtt;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
Time
|
||||
TcpGeneralTest::GetClockGranularity (SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_senderSocket)->m_clockGranularity;
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
return DynamicCast<TcpSocketMsgBase> (m_receiverSocket)->m_clockGranularity;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpGeneralTest::SetRcvBufSize (SocketWho who, uint32_t size)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
m_senderSocket->SetRcvBufSize (size);
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
m_receiverSocket->SetRcvBufSize (size);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Not defined");
|
||||
}
|
||||
}
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (TcpSocketMsgBase);
|
||||
|
||||
TypeId
|
||||
TcpSocketMsgBase::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpSocketMsgBase")
|
||||
.SetParent<TcpSocketBase> ()
|
||||
.SetGroupName ("Internet")
|
||||
.AddConstructor<TcpSocketMsgBase> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
Ptr<TcpSocketBase>
|
||||
TcpSocketMsgBase::Fork (void)
|
||||
{
|
||||
return CopyObject<TcpSocketMsgBase> (this);
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketMsgBase::SetRcvAckCb (AckManagementCallback cb)
|
||||
{
|
||||
NS_ASSERT (!cb.IsNull ());
|
||||
m_rcvAckCb = cb;
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketMsgBase::SetProcessedAckCb (AckManagementCallback cb)
|
||||
{
|
||||
NS_ASSERT (!cb.IsNull ());
|
||||
m_processedAckCb = cb;
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketMsgBase::SetRetransmitCb (RetrCallback cb)
|
||||
{
|
||||
NS_ASSERT (!cb.IsNull ());
|
||||
m_retrCallback = cb;
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketMsgBase::ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader)
|
||||
{
|
||||
NS_ASSERT (!(m_rcvAckCb.IsNull () || m_processedAckCb.IsNull ()));
|
||||
m_rcvAckCb (packet, tcpHeader, this);
|
||||
|
||||
TcpSocketBase::ReceivedAck (packet, tcpHeader);
|
||||
|
||||
m_processedAckCb (packet, tcpHeader, this);
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketMsgBase::Retransmit ()
|
||||
{
|
||||
TcpSocketBase::Retransmit ();
|
||||
|
||||
m_retrCallback (m_tcb, this);
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketMsgBase::SetForkCb (Callback<void, Ptr<TcpSocketMsgBase> > cb)
|
||||
{
|
||||
NS_ASSERT (!cb.IsNull ());
|
||||
m_forkCb = cb;
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketMsgBase::CompleteFork (Ptr<Packet> p, const TcpHeader &tcpHeader,
|
||||
const Address &fromAddress, const Address &toAddress)
|
||||
{
|
||||
TcpSocketBase::CompleteFork (p, tcpHeader, fromAddress, toAddress);
|
||||
|
||||
if (!m_forkCb.IsNull ())
|
||||
{
|
||||
m_forkCb (this);
|
||||
}
|
||||
}
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (TcpSocketSmallAcks);
|
||||
|
||||
TypeId
|
||||
TcpSocketSmallAcks::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpSocketSmallAcks")
|
||||
.SetParent<TcpSocketMsgBase> ()
|
||||
.SetGroupName ("Internet")
|
||||
.AddConstructor<TcpSocketSmallAcks> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Send empty packet, copied/pasted from TcpSocketBase
|
||||
*
|
||||
* The rationale for copying/pasting is that we need to edit a little the
|
||||
* code inside. Since there isn't a well-defined division of duties,
|
||||
* we are forced to do this.
|
||||
*/
|
||||
void
|
||||
TcpSocketSmallAcks::SendEmptyPacket (uint8_t flags)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet> ();
|
||||
TcpHeader header;
|
||||
SequenceNumber32 s = m_nextTxSequence;
|
||||
|
||||
/*
|
||||
* Add tags for each socket option.
|
||||
* Note that currently the socket adds both IPv4 tag and IPv6 tag
|
||||
* if both options are set. Once the packet got to layer three, only
|
||||
* the corresponding tags will be read.
|
||||
*/
|
||||
if (IsManualIpTos ())
|
||||
{
|
||||
SocketIpTosTag ipTosTag;
|
||||
ipTosTag.SetTos (GetIpTos ());
|
||||
p->AddPacketTag (ipTosTag);
|
||||
}
|
||||
|
||||
if (IsManualIpv6Tclass ())
|
||||
{
|
||||
SocketIpv6TclassTag ipTclassTag;
|
||||
ipTclassTag.SetTclass (GetIpv6Tclass ());
|
||||
p->AddPacketTag (ipTclassTag);
|
||||
}
|
||||
|
||||
if (IsManualIpTtl ())
|
||||
{
|
||||
SocketIpTtlTag ipTtlTag;
|
||||
ipTtlTag.SetTtl (GetIpTtl ());
|
||||
p->AddPacketTag (ipTtlTag);
|
||||
}
|
||||
|
||||
if (IsManualIpv6HopLimit ())
|
||||
{
|
||||
SocketIpv6HopLimitTag ipHopLimitTag;
|
||||
ipHopLimitTag.SetHopLimit (GetIpv6HopLimit ());
|
||||
p->AddPacketTag (ipHopLimitTag);
|
||||
}
|
||||
|
||||
if (m_endPoint == 0 && m_endPoint6 == 0)
|
||||
{
|
||||
NS_LOG_WARN ("Failed to send empty packet due to null endpoint");
|
||||
return;
|
||||
}
|
||||
if (flags & TcpHeader::FIN)
|
||||
{
|
||||
flags |= TcpHeader::ACK;
|
||||
}
|
||||
else if (m_state == FIN_WAIT_1 || m_state == LAST_ACK || m_state == CLOSING)
|
||||
{
|
||||
++s;
|
||||
}
|
||||
|
||||
bool hasSyn = flags & TcpHeader::SYN;
|
||||
bool hasFin = flags & TcpHeader::FIN;
|
||||
bool isAck = flags == TcpHeader::ACK;
|
||||
|
||||
header.SetFlags (flags);
|
||||
header.SetSequenceNumber (s);
|
||||
|
||||
// Actual division in small acks.
|
||||
if (hasSyn || hasFin)
|
||||
{
|
||||
header.SetAckNumber (m_rxBuffer->NextRxSequence ());
|
||||
}
|
||||
else
|
||||
{
|
||||
SequenceNumber32 ackSeq;
|
||||
|
||||
ackSeq = m_lastAckedSeq + m_bytesToAck;
|
||||
|
||||
if (m_bytesLeftToBeAcked == 0 && m_rxBuffer->NextRxSequence () > m_lastAckedSeq)
|
||||
{
|
||||
m_bytesLeftToBeAcked = m_rxBuffer->NextRxSequence ().GetValue () - 1 - m_bytesToAck;
|
||||
}
|
||||
else if (m_bytesLeftToBeAcked > 0 && m_rxBuffer->NextRxSequence () > m_lastAckedSeq)
|
||||
{
|
||||
m_bytesLeftToBeAcked -= m_bytesToAck;
|
||||
}
|
||||
|
||||
NS_LOG_LOGIC ("Acking up to " << ackSeq << " remaining bytes: " << m_bytesLeftToBeAcked);
|
||||
|
||||
header.SetAckNumber (ackSeq);
|
||||
m_lastAckedSeq = ackSeq;
|
||||
}
|
||||
|
||||
// end of division in small acks
|
||||
|
||||
if (m_endPoint != 0)
|
||||
{
|
||||
header.SetSourcePort (m_endPoint->GetLocalPort ());
|
||||
header.SetDestinationPort (m_endPoint->GetPeerPort ());
|
||||
}
|
||||
else
|
||||
{
|
||||
header.SetSourcePort (m_endPoint6->GetLocalPort ());
|
||||
header.SetDestinationPort (m_endPoint6->GetPeerPort ());
|
||||
}
|
||||
AddOptions (header);
|
||||
header.SetWindowSize (AdvertisedWindowSize ());
|
||||
|
||||
// RFC 6298, clause 2.4
|
||||
m_rto = Max (m_rtt->GetEstimate () + Max (m_clockGranularity, m_rtt->GetVariation () * 4), m_minRto);
|
||||
|
||||
if (hasSyn)
|
||||
{
|
||||
if (m_synCount == 0)
|
||||
{ // No more connection retries, give up
|
||||
NS_LOG_LOGIC ("Connection failed.");
|
||||
m_rtt->Reset (); //According to recommendation -> RFC 6298
|
||||
CloseAndNotify ();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{ // Exponential backoff of connection time out
|
||||
int backoffCount = 0x1 << (m_synRetries - m_synCount);
|
||||
m_rto = m_cnTimeout * backoffCount;
|
||||
m_synCount--;
|
||||
}
|
||||
}
|
||||
if (m_endPoint != 0)
|
||||
{
|
||||
m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (),
|
||||
m_endPoint->GetPeerAddress (), m_boundnetdevice);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tcp->SendPacket (p, header, m_endPoint6->GetLocalAddress (),
|
||||
m_endPoint6->GetPeerAddress (), m_boundnetdevice);
|
||||
}
|
||||
|
||||
m_txTrace (p, header, this);
|
||||
|
||||
if (flags & TcpHeader::ACK)
|
||||
{ // If sending an ACK, cancel the delay ACK as well
|
||||
m_delAckEvent.Cancel ();
|
||||
m_delAckCount = 0;
|
||||
}
|
||||
if (m_retxEvent.IsExpired () && (hasSyn || hasFin) && !isAck )
|
||||
{ // Retransmit SYN / SYN+ACK / FIN / FIN+ACK to guard against lost
|
||||
NS_LOG_LOGIC ("Schedule retransmission timeout at time "
|
||||
<< Simulator::Now ().GetSeconds () << " to expire at time "
|
||||
<< (Simulator::Now () + m_rto.Get ()).GetSeconds ());
|
||||
m_retxEvent = Simulator::Schedule (m_rto, &TcpSocketSmallAcks::SendEmptyPacket, this, flags);
|
||||
}
|
||||
|
||||
// send another ACK if bytes remain
|
||||
if (m_bytesLeftToBeAcked > 0 && m_rxBuffer->NextRxSequence () > m_lastAckedSeq)
|
||||
{
|
||||
SendEmptyPacket (flags);
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<TcpSocketBase>
|
||||
TcpSocketSmallAcks::Fork (void)
|
||||
{
|
||||
return CopyObject<TcpSocketSmallAcks> (this);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
668
src/internet/test/tcp-general-test.h
Normal file
668
src/internet/test/tcp-general-test.h
Normal file
@@ -0,0 +1,668 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2015 Natale Patriciello <natale.patriciello@gmail.com>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#ifndef TCPGENERALTEST_H
|
||||
#define TCPGENERALTEST_H
|
||||
|
||||
#include "ns3/simple-net-device.h"
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/tcp-socket-base.h"
|
||||
#include "ns3/test.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Class for inserting callbacks special points of the flow of TCP sockets
|
||||
*
|
||||
* This subclass is born to extend TcpSocketBase, inserting callbacks in certain
|
||||
* points of the flow, to be used in testing to check certain values or flow
|
||||
* directions.
|
||||
*
|
||||
* There isn't the necessity to fill TcpSocketBase of TracedCallbacks; the rationale
|
||||
* is to maintain the base class as clean as possible.
|
||||
*
|
||||
* To be fair with testing, this class should NOT modify the behavior of TcpSocketBase.
|
||||
*
|
||||
* \see SetRcvAckCb
|
||||
* \see SetProcessedAckCb
|
||||
* \see SetRetransmitCb
|
||||
*/
|
||||
class TcpSocketMsgBase : public TcpSocketBase
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
TcpSocketMsgBase () : TcpSocketBase ()
|
||||
{
|
||||
}
|
||||
|
||||
TcpSocketMsgBase (const TcpSocketMsgBase &other) : TcpSocketBase (other)
|
||||
{
|
||||
m_rcvAckCb = other.m_rcvAckCb;
|
||||
m_processedAckCb = other.m_processedAckCb;
|
||||
m_retrCallback = other.m_retrCallback;
|
||||
m_forkCb = other.m_forkCb;
|
||||
}
|
||||
|
||||
typedef Callback<void, Ptr<const Packet>, const TcpHeader&,
|
||||
Ptr<const TcpSocketBase> > AckManagementCallback;
|
||||
typedef Callback<void, Ptr<const TcpSocketState>,
|
||||
Ptr<const TcpSocketBase> > RetrCallback;
|
||||
|
||||
/**
|
||||
* \brief Set the callback invoked when an ACK is received (at the beginning
|
||||
* of the processing)
|
||||
*
|
||||
* \param cb callback
|
||||
*/
|
||||
void SetRcvAckCb (AckManagementCallback cb);
|
||||
|
||||
/**
|
||||
* \brief Set the callback invoked when an ACK is received and processed
|
||||
* (at the end of the processing)
|
||||
*
|
||||
* \param cb callback
|
||||
*/
|
||||
void SetProcessedAckCb (AckManagementCallback cb);
|
||||
|
||||
/**
|
||||
* \brief Set the callback invoked after the processing of a retransmit timeout
|
||||
*
|
||||
* \param cb callback
|
||||
*/
|
||||
void SetRetransmitCb (RetrCallback cb);
|
||||
|
||||
/**
|
||||
* \brief Set the callback invoked after the forking
|
||||
* \param cb callback
|
||||
*/
|
||||
void SetForkCb (Callback<void, Ptr<TcpSocketMsgBase> > cb);
|
||||
|
||||
protected:
|
||||
virtual void ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader);
|
||||
virtual void Retransmit (void);
|
||||
virtual Ptr<TcpSocketBase> Fork (void);
|
||||
virtual void CompleteFork (Ptr<Packet> p, const TcpHeader& tcpHeader,
|
||||
const Address& fromAddress, const Address& toAddress);
|
||||
|
||||
private:
|
||||
AckManagementCallback m_rcvAckCb;
|
||||
AckManagementCallback m_processedAckCb;
|
||||
RetrCallback m_retrCallback;
|
||||
Callback<void, Ptr<TcpSocketMsgBase> > m_forkCb;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief A TCP socket which sends ACKs smaller than the segment received.
|
||||
*
|
||||
* Usually, a TCP socket which receives the sequence number "x" replies with
|
||||
* an ACK to "x+1". What happen if a malicious socket sends smaller ACKs
|
||||
* (e.g. two ACKs, one for "x/2", and the other for "x+1") ? A TCP implementation
|
||||
* should avoid to artificially increase the congestion window, thinking of
|
||||
* having ACKed 2 segments instead of 1.
|
||||
*
|
||||
* Set the number of bytes that should be acked in each ACK packet with
|
||||
* SetBytesToAck.
|
||||
*
|
||||
* \see TcpSlowStartAttackerTest
|
||||
*/
|
||||
class TcpSocketSmallAcks : public TcpSocketMsgBase
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
TcpSocketSmallAcks ()
|
||||
: TcpSocketMsgBase (),
|
||||
m_bytesToAck (125),
|
||||
m_bytesLeftToBeAcked (0),
|
||||
m_lastAckedSeq (1)
|
||||
{
|
||||
}
|
||||
|
||||
TcpSocketSmallAcks (const TcpSocketSmallAcks &other) : TcpSocketMsgBase (other),
|
||||
m_bytesToAck (other.m_bytesToAck),
|
||||
m_bytesLeftToBeAcked (other.m_bytesLeftToBeAcked),
|
||||
m_lastAckedSeq (other.m_lastAckedSeq)
|
||||
{
|
||||
}
|
||||
|
||||
void SetBytesToAck (uint32_t bytes)
|
||||
{
|
||||
m_bytesToAck = bytes;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SendEmptyPacket (uint8_t flags);
|
||||
Ptr<TcpSocketBase> Fork (void);
|
||||
|
||||
uint32_t m_bytesToAck;
|
||||
uint32_t m_bytesLeftToBeAcked;
|
||||
SequenceNumber32 m_lastAckedSeq;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief General infrastructure for TCP testing
|
||||
*
|
||||
* The class provides a simple setup for a connection testing. Implement
|
||||
* or modify the virtual methods in order to install a specified
|
||||
* channel, a specified socket and a specified error model on this simulation.
|
||||
* Default values are a null error model, and as a channel a SimpleChannel with
|
||||
* the propagation delay set through the constructor.
|
||||
*
|
||||
* Check DoRun documentation for more information on the environment setup.
|
||||
*
|
||||
* Apart from setting up the environment for testing, subclassing permits also
|
||||
* to track and check what is happening inside the two connected sockets. Thanks
|
||||
* to TcpSocketMsgBase, there are many information provided to children:
|
||||
*
|
||||
* - Tracing of states inside the state machines (TCP and ACK ones, through
|
||||
* functions AckStateTrace and TcpStateTrace)
|
||||
* - cWnd tracing (through CWndTrace)
|
||||
* - Socket closing: error state, or normal state (NormalClose and ErrorClose)
|
||||
* - Packet drop, inside queue or over the link (QueueDrop, PhyDrop)
|
||||
* - Ack received (RcvAck) and Ack processed (ProcessedAck). The first is used to
|
||||
* signal that an ACK has been received; after the processing of it, the Second
|
||||
* is called
|
||||
* - A packet is transmitted to IP layer or received from IP layer (Tx and Rx)
|
||||
* - The RTO expires (RTOExpired)
|
||||
*
|
||||
* The default version of such methods is empty; implement their behavior differently,
|
||||
* based on what you want to test. Default is empty to avoid the need to implement
|
||||
* useless pure virtual function.
|
||||
*
|
||||
* If you need values from TcpSocketBase, thanks to the friend relationship between
|
||||
* this class and TcpSocketBase itself you can get it. Remember that friendship
|
||||
* isn't passed by inheritance, so the way to go is to write a Getters (like
|
||||
* GetSegSize) and call it in the subclass.
|
||||
*
|
||||
* \see DoRun
|
||||
* \see TcpSocketMsgBase
|
||||
*/
|
||||
class TcpGeneralTest : public TestCase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief TcpGeneralTest constructor
|
||||
*
|
||||
* \param pktSize application packet size
|
||||
* \param pktCount count of application packet to generate
|
||||
* \param pktInterval (application) interval between each generated packet
|
||||
* \param propagationDelay propagation delay of the channel
|
||||
* \param startTime time of the first application-generated packet
|
||||
* \param mtu MTU of the environment
|
||||
* \param desc description of the test
|
||||
*/
|
||||
TcpGeneralTest (const std::string &desc,
|
||||
uint32_t pktSize = 500,
|
||||
uint32_t pktCount = 10,
|
||||
const Time& pktInterval = Seconds (0.01),
|
||||
const Time& propagationDelay = Seconds (0.5),
|
||||
const Time& startTime = Seconds (10),
|
||||
uint32_t initialSlowStartThresh = 0xffff,
|
||||
uint32_t initialCwnd = 1,
|
||||
uint32_t segmentSize = 500,
|
||||
TypeId congestionControl = TcpNewReno::GetTypeId (),
|
||||
uint32_t mtu = 1500);
|
||||
~TcpGeneralTest ();
|
||||
|
||||
/**
|
||||
* \brief Used as parameter of methods, specifies on what node
|
||||
* the caller is interested (e.g. GetSegSize).
|
||||
*/
|
||||
enum SocketWho
|
||||
{
|
||||
SENDER, //!< Sender node
|
||||
RECEIVER //!< Receiver node
|
||||
};
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Create and return the channel installed between the two socket
|
||||
*
|
||||
* \return A SimpleChannel subclass
|
||||
*/
|
||||
virtual Ptr<SimpleChannel> CreateChannel ();
|
||||
|
||||
/**
|
||||
* \brief Create and return the error model to install in the sender node
|
||||
*
|
||||
* \return sender error model
|
||||
*/
|
||||
virtual Ptr<ErrorModel> CreateSenderErrorModel ();
|
||||
|
||||
/**
|
||||
* \brief Create and return the error model to install in the receiver node
|
||||
*
|
||||
* \return receiver error model
|
||||
*/
|
||||
virtual Ptr<ErrorModel> CreateReceiverErrorModel ();
|
||||
|
||||
/**
|
||||
* \brief Create and install the socket to install on the receiver
|
||||
* \param node receiver node pointer
|
||||
* \return the socket to be installed in the receiver
|
||||
*/
|
||||
virtual Ptr<TcpSocketMsgBase> CreateReceiverSocket (Ptr<Node> node);
|
||||
|
||||
/**
|
||||
* \brief Create and install the socket to install on the sender
|
||||
* \param node sender node pointer
|
||||
* \return the socket to be installed in the sender
|
||||
*/
|
||||
virtual Ptr<TcpSocketMsgBase> CreateSenderSocket (Ptr<Node> node);
|
||||
|
||||
/**
|
||||
* \brief Create a socket
|
||||
*
|
||||
* \param node associated node
|
||||
* \param congControl congestion control
|
||||
* \return a pointer to the newer created socket
|
||||
*/
|
||||
virtual Ptr<TcpSocketMsgBase> CreateSocket (Ptr<Node> node, TypeId socketType,
|
||||
TypeId congControl);
|
||||
|
||||
/**
|
||||
* \brief Get the pointer to a previously created sender socket
|
||||
* \return ptr to sender socket or 0
|
||||
*/
|
||||
Ptr<TcpSocketMsgBase> GetSenderSocket ()
|
||||
{
|
||||
return m_senderSocket;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the pointer to a previously created receiver socket
|
||||
* \return ptr to receiver socket or 0
|
||||
*/
|
||||
Ptr<TcpSocketMsgBase> GetReceiverSocket ()
|
||||
{
|
||||
return m_receiverSocket;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Execute the tcp test
|
||||
*
|
||||
* As environment, two socket are connected through a SimpleChannel. Each device
|
||||
* has an MTU of 1500 bytes, and the application starts to send packet at
|
||||
* 10s of simulated time, through SendPacket.
|
||||
*/
|
||||
virtual void DoRun (void);
|
||||
|
||||
/**
|
||||
* \brief Teardown the TCP test
|
||||
*/
|
||||
virtual void DoTeardown (void);
|
||||
|
||||
/**
|
||||
* \brief Packet received
|
||||
*
|
||||
* The method processes the packet (application-layer)
|
||||
* \param socket socket which has received the packet
|
||||
*/
|
||||
virtual void ReceivePacket (Ptr<Socket> socket);
|
||||
|
||||
/**
|
||||
* \brief Send packets to other endpoint
|
||||
*
|
||||
* \param socket Socket
|
||||
* \param pktSize size of the packet
|
||||
* \param pktCount number of packets to send
|
||||
* \param pktInterval interval between packet (application-level)
|
||||
*/
|
||||
void SendPacket (Ptr<Socket> socket, uint32_t pktSize,
|
||||
uint32_t pktCount, Time pktInterval);
|
||||
|
||||
/**
|
||||
* \brief Get the segment size of the node specified
|
||||
*
|
||||
* \param who node to get the parameter from
|
||||
*
|
||||
* \return segment size of the specified node
|
||||
*/
|
||||
uint32_t GetSegSize (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Get the retransmission threshold
|
||||
* \param who node to get the parameter from
|
||||
* \return retransmission threshold
|
||||
*/
|
||||
uint32_t GetReTxThreshold (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Get the number of dupack received
|
||||
* \param who node to get the parameter from
|
||||
* \return number of dupack
|
||||
*/
|
||||
uint32_t GetDupAckCount (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Get the number of delayed ack (if present)
|
||||
* \param who node to get the parameter from
|
||||
* \return number of ack we will wait before sending an ACK
|
||||
*/
|
||||
uint32_t GetDelAckCount (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Get the timeout of delayed ack (if present)
|
||||
* \param who node to get the parameter from
|
||||
* \return time we will wait before sending an ACK
|
||||
*/
|
||||
Time GetDelAckTimeout (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Get the retransmission time
|
||||
*
|
||||
* \param who node to get the parameter from
|
||||
* \return calculated RTO time
|
||||
*/
|
||||
Time GetRto (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Get the minimun RTO attribute
|
||||
*
|
||||
* \param who node to get the parameter from
|
||||
* \return minimum RTO time
|
||||
*/
|
||||
Time GetMinRto (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Get the retransmission time for the SYN segments
|
||||
*
|
||||
* \param who node to get the parameter from
|
||||
* \return SYN segments RTO time
|
||||
*/
|
||||
Time GetConnTimeout (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Get the Rtt estimator of the socket
|
||||
*
|
||||
* \param who node to get the parameter from
|
||||
* \return Rtt estimator
|
||||
*/
|
||||
Ptr<RttEstimator> GetRttEstimator (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Get the clock granularity attribute
|
||||
*
|
||||
* \param who node to get the parameter from
|
||||
* \return clock granularity
|
||||
*/
|
||||
Time GetClockGranularity (SocketWho who);
|
||||
|
||||
/**
|
||||
* \brief Forcefully set a defined size for rx buffer
|
||||
*
|
||||
* \param who socket to force
|
||||
* \param size size of the rx buffer
|
||||
*/
|
||||
void SetRcvBufSize (SocketWho who, uint32_t size);
|
||||
|
||||
/**
|
||||
* \brief State on Ack state machine changes
|
||||
* \param oldValue old value
|
||||
* \param newValue new value
|
||||
*/
|
||||
virtual void AckStateTrace (const TcpSocketState::TcpAckState_t oldValue,
|
||||
const TcpSocketState::TcpAckState_t newValue)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Congestion window changes
|
||||
*
|
||||
* \param oldValue old value
|
||||
* \param newValue new value
|
||||
*/
|
||||
virtual void CWndTrace (uint32_t oldValue, uint32_t newValue)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Socket closed normally
|
||||
* \param who the socket closed (SENDER or RECEIVER)
|
||||
*/
|
||||
virtual void NormalClose (SocketWho who)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Socket closed with an error
|
||||
*
|
||||
* \param who the socket closed (SENDER or RECEIVER)
|
||||
*/
|
||||
virtual void ErrorClose (SocketWho who)
|
||||
{
|
||||
/** \todo indicate the error */
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Drop on the queue
|
||||
* \param who where the drop occurred (SENDER or RECEIVER)
|
||||
*/
|
||||
virtual void QueueDrop (SocketWho who)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Link drop
|
||||
* \param who where the drop occurred (SENDER or RECEIVER)
|
||||
*/
|
||||
virtual void PhyDrop (SocketWho who)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Received ack
|
||||
*
|
||||
* Invoked when an ACK is received (no processing is done yet)
|
||||
*
|
||||
* \param tcb Transmission Control Block
|
||||
* \param h the header of segment
|
||||
* \param who the socket which has received the ACK (SENDER or RECEIVER)
|
||||
*/
|
||||
virtual void RcvAck (const Ptr<const TcpSocketState> tcb,
|
||||
const TcpHeader& h, SocketWho who)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Processed ack
|
||||
*
|
||||
* Invoked after the processing of the ACK
|
||||
*
|
||||
* \param tcb Transmission Control Block
|
||||
* \param h the header of segment
|
||||
* \param who the socket which has processed the ACK (SENDER or RECEIVER)
|
||||
*/
|
||||
virtual void ProcessedAck (const Ptr<const TcpSocketState> tcb,
|
||||
const TcpHeader& h, SocketWho who)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Packet transmitted down to IP layer
|
||||
*
|
||||
* \param p packet
|
||||
* \param h header
|
||||
* \param who the socket which has received the packet (SENDER or RECEIVER)
|
||||
*/
|
||||
virtual void Tx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Packet received from IP layer
|
||||
*
|
||||
* \param p packet
|
||||
* \param h header
|
||||
* \param who the socket which has received the packet (SENDER or RECEIVER)
|
||||
*/
|
||||
virtual void Rx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Rto has expired
|
||||
*
|
||||
* \param tcb Transmission control block
|
||||
* \param who where the RTO has expired (SENDER or RECEIVER)
|
||||
*/
|
||||
virtual void RTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Performs the (eventual) final checks through test asserts
|
||||
*
|
||||
*/
|
||||
virtual void FinalChecks ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the channel Propagation Delay
|
||||
* \return propagation delay of the channel
|
||||
*/
|
||||
Time GetPropagationDelay () const
|
||||
{
|
||||
return m_propagationDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the data start time
|
||||
* \return start time of data packets
|
||||
*/
|
||||
Time GetStartTime () const
|
||||
{
|
||||
return m_startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the MTU of the environment
|
||||
* \return MTU of the environment
|
||||
*/
|
||||
uint32_t GetMtu () const
|
||||
{
|
||||
return m_mtu;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the application packet size
|
||||
* \return application packet size
|
||||
*/
|
||||
uint32_t GetPktSize () const
|
||||
{
|
||||
return m_pktSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the number of application packets
|
||||
* \return count of application packets to be generated
|
||||
*/
|
||||
uint32_t GetPktCount () const
|
||||
{
|
||||
return m_pktCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the interval to wait for each packet sent down from application
|
||||
* to TCP
|
||||
* \return interval between packet
|
||||
*/
|
||||
Time GetPktInterval () const
|
||||
{
|
||||
return m_interPacketInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the initial slow start threshold
|
||||
* \return initial slow start threshold
|
||||
*/
|
||||
uint32_t GetInitialSsThresh () const
|
||||
{
|
||||
return m_initialSlowStartThresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the initial congestion window
|
||||
* \return initial cwnd
|
||||
*/
|
||||
uint32_t GetInitialCwnd () const
|
||||
{
|
||||
return m_initialCwnd;
|
||||
}
|
||||
|
||||
|
||||
TypeId m_congControlTypeId; //!< Congestion control
|
||||
|
||||
private:
|
||||
// Member variables, accessible through getters
|
||||
// giving write access to subclass can be dangerous
|
||||
Time m_propagationDelay; //!< Propagation delay of the channel
|
||||
|
||||
Time m_startTime; //!< Data transmission time
|
||||
uint32_t m_mtu; //!< MTU of the environment
|
||||
|
||||
uint32_t m_pktSize; //!< Size of the application packet
|
||||
uint32_t m_pktCount; //!< Count of the application packet
|
||||
Time m_interPacketInterval; //!< Time between sending application packet
|
||||
// down to tcp socket
|
||||
uint32_t m_initialSlowStartThresh; //!< Initial slow start threshold
|
||||
uint32_t m_initialCwnd; //!< Initial congestion window
|
||||
uint32_t m_segmentSize; //!< Segment size
|
||||
|
||||
Ptr<TcpSocketMsgBase> m_senderSocket; //!< Pointer to sender socket
|
||||
Ptr<TcpSocketMsgBase> m_receiverSocket; //!< Pointer to receiver socket
|
||||
|
||||
private:
|
||||
// De-multiplexing callbacks.
|
||||
void NormalCloseCb (Ptr<Socket> socket);
|
||||
void ErrorCloseCb (Ptr<Socket> socket);
|
||||
void QueueDropCb (std::string context, Ptr<const Packet> p);
|
||||
void PhyDropCb (std::string context, Ptr<const Packet> p);
|
||||
void RcvAckCb (Ptr<const Packet> p, const TcpHeader& h,
|
||||
Ptr<const TcpSocketBase> tcp);
|
||||
void ProcessedAckCb (Ptr<const Packet> p, const TcpHeader& h,
|
||||
Ptr<const TcpSocketBase> tcp);
|
||||
void TxPacketCb (const Ptr<const Packet> p, const TcpHeader& h,
|
||||
const Ptr<const TcpSocketBase> tcp);
|
||||
void RxPacketCb (const Ptr<const Packet> p, const TcpHeader& h,
|
||||
const Ptr<const TcpSocketBase> tcp);
|
||||
void RtoExpiredCb (const Ptr<const TcpSocketState> tcb,
|
||||
const Ptr<const TcpSocketBase> tcp);
|
||||
void ForkCb (Ptr<TcpSocketMsgBase> tcp);
|
||||
void HandleAccept (Ptr<Socket> socket, const Address& from);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Convenience function to retrieve the ACK state from a TCB
|
||||
*
|
||||
* \param tcb Transmission control block
|
||||
* \return the state of the ACK state machine
|
||||
*/
|
||||
static inline TcpSocketState::TcpAckState_t
|
||||
GetAckStateFrom (Ptr<const TcpSocketState> tcb)
|
||||
{
|
||||
return tcb->m_ackState.Get ();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif // TCPGENERALTEST_H
|
||||
|
||||
@@ -231,6 +231,7 @@ def build(bld):
|
||||
'test/tcp-wscaling-test.cc',
|
||||
'test/tcp-option-test.cc',
|
||||
'test/tcp-header-test.cc',
|
||||
'test/tcp-general-test.cc',
|
||||
'test/udp-test.cc',
|
||||
'test/ipv6-address-generator-test-suite.cc',
|
||||
'test/ipv6-dual-stack-test-suite.cc',
|
||||
|
||||
Reference in New Issue
Block a user