merge
This commit is contained in:
57
CHANGES.html
57
CHANGES.html
@@ -217,6 +217,63 @@ Rename all instances method names using "Set..Parameter" to "Set..Attribute"
|
||||
|
||||
<h2>changed behavior:</h2>
|
||||
<ul>
|
||||
|
||||
<li>07-09-2008; changeset
|
||||
<a href="http://code.nsnam.org/ns-3-dev/rev/5d836ab1523b">5d836ab1523b</a></li>
|
||||
<ul>
|
||||
<li>
|
||||
Implement a finite receive buffer for TCP<br>
|
||||
The native TCP model in TcpSocketImpl did not support a finite receive buffer.
|
||||
This changeset adds the following functionality in this regard:
|
||||
<ul>
|
||||
<li>
|
||||
Being able to set the receiver buffer size through the attributes system.
|
||||
</li>
|
||||
<li>
|
||||
This receiver buffer size is now correctly exported in the TCP header as the
|
||||
advertised window. Prior to this changeset, the TCP header advertised window
|
||||
was set to the maximum size of 2^16 bytes.
|
||||
window
|
||||
</li>
|
||||
<li>
|
||||
The aforementioned window size is correctly used for flow control, i.e. the
|
||||
sending TCP will not send more data than available space in the receiver's
|
||||
buffer.
|
||||
</li>
|
||||
<li>
|
||||
In the case of a receiver window collapse, when a advertised zero-window
|
||||
packet is received, the sender enters the persist probing state in which
|
||||
it sends probe packets with one payload byte at exponentially backed-off
|
||||
intervals up to 60s. The reciever will continue to send advertised
|
||||
zero-window ACKs of the old data so long as the receiver buffer remains full.
|
||||
When the receiver window clears up due to an application read, the TCP
|
||||
will finally ACK the probe byte, and update its advertised window appropriately.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
See
|
||||
<a href="http://www.nsnam.org/bugzilla/show_bug.cgi?id=239"> bug 239 </a> for
|
||||
more.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>07-09-2008; changeset
|
||||
<a href="http://code.nsnam.org/ns-3-dev/rev/7afa66c2b291">7afa66c2b291</a></li>
|
||||
<ul>
|
||||
<li>
|
||||
Add correct FIN exchange behavior during TCP closedown<br>
|
||||
The behavior of the native TcpSocketImpl TCP model was such that the final
|
||||
FIN exchange was not correct, i.e. calling Socket::Close didn't send a FIN
|
||||
packet, and even if it had, the ACK never came back, and even if it had, the
|
||||
ACK would have incorrect sequence number. All these various problems have been
|
||||
addressed by this changeset. See
|
||||
<a href="http://www.nsnam.org/bugzilla/show_bug.cgi?id=242"> bug 242 </a> for
|
||||
more.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li> 28-07-2008; changeset
|
||||
<a href="http://code.nsnam.org/ns-3-dev/rev/6f68f1044df1">6f68f1044df1</a>
|
||||
<ul>
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// 10Mb/s, 10ms 10Mb/s, 10ms
|
||||
// n0-----------------n1-----------------n2
|
||||
//
|
||||
//
|
||||
// - CBR traffic for 1000 seconds
|
||||
// - Tracing of queues and packet receptions to file
|
||||
// "tcp-large-transfer.tr"
|
||||
// - pcap traces also generated in the following files
|
||||
// "tcp-large-transfer-$n-$i.pcap" where n and i represent node and interface
|
||||
// numbers respectively
|
||||
// Usage (e.g.): ./waf --run tcp-large-transfer
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/common-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/global-route-manager.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpErrors");
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("TcpSocketImpl", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("PacketSink", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("TcpErrors", LOG_LEVEL_ALL);
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create three nodes. The first container contains
|
||||
// nodes 0 and 1 from the diagram above, and the second one contains nodes
|
||||
// 1 and 2. This reflects the channel connectivity, and will be used to
|
||||
// install the network interfaces and connect them with a channel.
|
||||
NodeContainer n0n1;
|
||||
n0n1.Create (2);
|
||||
|
||||
NodeContainer n1n2;
|
||||
n1n2.Add (n0n1.Get (1));
|
||||
n1n2.Create (1);
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
// First make and configure the helper, so that it will put the appropriate
|
||||
// parameters on the network interfaces and channels we are about to install.
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate(10000000)));
|
||||
p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds(10)));
|
||||
|
||||
// And then install devices and channels connecting our topology.
|
||||
NetDeviceContainer d0d1 = p2p.Install (n0n1);
|
||||
NetDeviceContainer d1d2 = p2p.Install (n1n2);
|
||||
|
||||
// Now add ip/tcp stack to all nodes.
|
||||
NodeContainer allNodes = NodeContainer (n0n1, n1n2.Get (1));
|
||||
InternetStackHelper internet;
|
||||
internet.Install (allNodes);
|
||||
|
||||
// Later, we add IP addresses.
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i0i1 = ipv4.Assign (d0d1);
|
||||
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i1i2 = ipv4.Assign (d1d2);
|
||||
|
||||
// and setup ip routing tables to get total ip-level connectivity.
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
|
||||
// Set up the sending CBR application
|
||||
uint16_t servPort = 50000;
|
||||
Address remoteAddress(InetSocketAddress(i1i2.GetAddress (1), servPort));
|
||||
OnOffHelper clientHelper ("ns3::TcpSocketFactory", remoteAddress);
|
||||
clientHelper.SetAttribute
|
||||
("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
clientHelper.SetAttribute
|
||||
("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
ApplicationContainer clientApp = clientHelper.Install(n0n1.Get(0));
|
||||
clientApp.Start (Seconds (1.0));
|
||||
clientApp.Stop (Seconds (10.0));
|
||||
|
||||
// Create a packet sink to receive at n2
|
||||
PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), servPort));
|
||||
ApplicationContainer sinkApp = sinkHelper.Install (n1n2.Get(1));
|
||||
sinkApp.Start (Seconds (1.0));
|
||||
sinkApp.Stop (Seconds (10.0));
|
||||
|
||||
// We're going to model a lossy channel
|
||||
RandomVariableValue u01(UniformVariable (0.0, 1.0));
|
||||
DoubleValue rate(0.001);
|
||||
Ptr<RateErrorModel> em1 =
|
||||
CreateObject<RateErrorModel> ("RanVar", u01, "ErrorRate", rate);
|
||||
Ptr<RateErrorModel> em2 =
|
||||
CreateObject<RateErrorModel> ("RanVar", u01, "ErrorRate", rate);
|
||||
//put error models on both netdevices of the router nodes so that there is
|
||||
//loss of both data and acks
|
||||
d0d1.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue (em1));
|
||||
d1d2.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue (em2));
|
||||
|
||||
//Ask for ASCII and pcap traces of network traffic
|
||||
std::ofstream ascii;
|
||||
ascii.open ("tcp-errors.tr");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
|
||||
PointToPointHelper::EnablePcapAll ("tcp-errors");
|
||||
|
||||
// Finally, set up the simulator to run for 1000 seconds.
|
||||
Simulator::Stop (Seconds(1000));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -132,6 +132,7 @@ int main (int argc, char *argv[])
|
||||
|
||||
ApplicationContainer apps = sink.Install (n1n2.Get (1));
|
||||
apps.Start (Seconds (0.0));
|
||||
apps.Stop (Seconds (3.0));
|
||||
|
||||
// Create a source to send packets from n0. Instead of a full Application
|
||||
// and the helper APIs you might see in other example files, this example
|
||||
|
||||
@@ -60,10 +60,6 @@ def build(bld):
|
||||
['point-to-point', 'internet-stack'])
|
||||
obj.source = 'tcp-large-transfer.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-errors',
|
||||
['point-to-point', 'internet-stack'])
|
||||
obj.source = 'tcp-errors.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-nsc-lfn',
|
||||
['point-to-point', 'internet-stack'])
|
||||
obj.source = 'tcp-nsc-lfn.cc'
|
||||
|
||||
@@ -131,7 +131,7 @@ Ptr<Packet> PendingData::CopyFromOffset (uint32_t s, uint32_t o)
|
||||
uint32_t s1 = std::min (s, SizeFromOffset (o)); // Insure not beyond end of data
|
||||
if (s1 == 0)
|
||||
{
|
||||
return 0; // No data requested
|
||||
return Create<Packet> (); // No data requested
|
||||
}
|
||||
if (data.size() != 0)
|
||||
{ // Actual data exists, make copy and return it
|
||||
|
||||
@@ -76,10 +76,13 @@ TcpSocketImpl::GetTypeId ()
|
||||
m_highestRxAck (0),
|
||||
m_lastRxAck (0),
|
||||
m_nextRxSequence (0),
|
||||
m_rxAvailable (0),
|
||||
m_rxBufSize (0),
|
||||
m_pendingData (0),
|
||||
m_rxWindowSize (0),
|
||||
m_persistTime (Seconds(6)), //XXX hook this into attributes?
|
||||
m_rtt (0),
|
||||
m_lastMeasuredRtt (Seconds(0.0)),
|
||||
m_rxAvailable (0)
|
||||
m_lastMeasuredRtt (Seconds(0.0))
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
@@ -112,20 +115,21 @@ TcpSocketImpl::TcpSocketImpl(const TcpSocketImpl& sock)
|
||||
m_highestRxAck (sock.m_highestRxAck),
|
||||
m_lastRxAck (sock.m_lastRxAck),
|
||||
m_nextRxSequence (sock.m_nextRxSequence),
|
||||
m_rxAvailable (0),
|
||||
m_rxBufSize (0),
|
||||
m_pendingData (0),
|
||||
m_segmentSize (sock.m_segmentSize),
|
||||
m_rxWindowSize (sock.m_rxWindowSize),
|
||||
m_advertisedWindowSize (sock.m_advertisedWindowSize),
|
||||
m_cWnd (sock.m_cWnd),
|
||||
m_ssThresh (sock.m_ssThresh),
|
||||
m_initialCWnd (sock.m_initialCWnd),
|
||||
m_persistTime (sock.m_persistTime),
|
||||
m_rtt (0),
|
||||
m_lastMeasuredRtt (Seconds(0.0)),
|
||||
m_cnTimeout (sock.m_cnTimeout),
|
||||
m_cnCount (sock.m_cnCount),
|
||||
m_rxAvailable (0),
|
||||
m_sndBufSize (sock.m_sndBufSize),
|
||||
m_rcvBufSize(sock.m_rcvBufSize)
|
||||
m_rxBufMaxSize(sock.m_rxBufMaxSize)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
NS_LOG_LOGIC("Invoked the copy constructor");
|
||||
@@ -176,7 +180,6 @@ TcpSocketImpl::SetNode (Ptr<Node> node)
|
||||
m_node = node;
|
||||
// Initialize some variables
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
m_rxWindowSize = m_advertisedWindowSize;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -212,6 +215,9 @@ TcpSocketImpl::Destroy (void)
|
||||
m_node = 0;
|
||||
m_endPoint = 0;
|
||||
m_tcp = 0;
|
||||
NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at "
|
||||
<< (Simulator::Now () +
|
||||
Simulator::GetDelayLeft (m_retxEvent)).GetSeconds());
|
||||
m_retxEvent.Cancel ();
|
||||
}
|
||||
int
|
||||
@@ -492,6 +498,7 @@ TcpSocketImpl::Recv (uint32_t maxSize, uint32_t flags)
|
||||
out[i->first] = i->second;
|
||||
}
|
||||
m_rxAvailable -= i->second->GetSize ();
|
||||
m_rxBufSize -= i->second->GetSize ();
|
||||
m_bufferedData.erase (i); // Remove from list
|
||||
}
|
||||
if (out.size() == 0)
|
||||
@@ -514,6 +521,7 @@ TcpSocketImpl::Recv (uint32_t maxSize, uint32_t flags)
|
||||
m_bufferedData[i->first+SequenceNumber(avail)]
|
||||
= i->second->CreateFragment(avail,i->second->GetSize()-avail);
|
||||
m_rxAvailable += i->second->GetSize()-avail;
|
||||
m_rxBufSize += i->second->GetSize()-avail;
|
||||
}
|
||||
}
|
||||
return outPacket;
|
||||
@@ -571,6 +579,13 @@ TcpSocketImpl::ForwardUp (Ptr<Packet> packet, Ipv4Address ipv4, uint16_t port)
|
||||
}
|
||||
}
|
||||
|
||||
if (m_rxWindowSize == 0 && tcpHeader.GetWindowSize () != 0)
|
||||
{ //persist probes end
|
||||
NS_LOG_LOGIC (this<<" Leaving zerowindow persist state");
|
||||
m_persistEvent.Cancel ();
|
||||
}
|
||||
m_rxWindowSize = tcpHeader.GetWindowSize (); //update the flow control window
|
||||
|
||||
Events_t event = SimulationSingleton<TcpStateMachine>::Get ()->FlagsEvent (tcpHeader.GetFlags () );
|
||||
Actions_t action = ProcessEvent (event); //updates the state
|
||||
Address address = InetSocketAddress (ipv4, port);
|
||||
@@ -632,7 +647,7 @@ Actions_t TcpSocketImpl::ProcessEvent (Events_t e)
|
||||
|
||||
void TcpSocketImpl::SendEmptyPacket (uint8_t flags)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << flags);
|
||||
NS_LOG_FUNCTION (this << (uint32_t)flags);
|
||||
Ptr<Packet> p = Create<Packet> ();
|
||||
TcpHeader header;
|
||||
|
||||
@@ -641,17 +656,21 @@ void TcpSocketImpl::SendEmptyPacket (uint8_t flags)
|
||||
header.SetAckNumber (m_nextRxSequence);
|
||||
header.SetSourcePort (m_endPoint->GetLocalPort ());
|
||||
header.SetDestinationPort (m_remotePort);
|
||||
header.SetWindowSize (m_advertisedWindowSize);
|
||||
header.SetWindowSize (AdvertisedWindowSize());
|
||||
m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (),
|
||||
m_remoteAddress);
|
||||
Time rto = m_rtt->RetransmitTimeout ();
|
||||
if (flags & TcpHeader::SYN)
|
||||
bool hasSyn = flags & TcpHeader::SYN;
|
||||
bool hasFin = flags & TcpHeader::FIN;
|
||||
bool isAck = flags == TcpHeader::ACK;
|
||||
if (hasSyn)
|
||||
{
|
||||
rto = m_cnTimeout;
|
||||
m_cnTimeout = m_cnTimeout + m_cnTimeout;
|
||||
m_cnCount--;
|
||||
}
|
||||
if (m_retxEvent.IsExpired () ) //no outstanding timer
|
||||
if (m_retxEvent.IsExpired () && (hasSyn || hasFin) && !isAck )
|
||||
//no outstanding timer
|
||||
{
|
||||
NS_LOG_LOGIC ("Schedule retransmission timeout at time "
|
||||
<< Simulator::Now ().GetSeconds () << " to expire at time "
|
||||
@@ -745,6 +764,13 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
|
||||
Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
|
||||
switch (a)
|
||||
{
|
||||
case ACK_TX:
|
||||
if(tcpHeader.GetFlags() & TcpHeader::FIN)
|
||||
{
|
||||
++m_nextRxSequence; //bump this to account for the FIN
|
||||
}
|
||||
SendEmptyPacket (TcpHeader::ACK);
|
||||
break;
|
||||
case SYN_ACK_TX:
|
||||
NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SYN_ACK_TX");
|
||||
// m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
|
||||
@@ -767,19 +793,20 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
|
||||
p, tcpHeader,fromAddress);
|
||||
return true;
|
||||
}
|
||||
// This is the cloned endpoint
|
||||
m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
|
||||
if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
|
||||
{
|
||||
m_localAddress = ipv4->GetAddress (localIfIndex);
|
||||
m_endPoint->SetLocalAddress (m_localAddress);
|
||||
// Leave local addr in the portmap to any, as the path from
|
||||
// remote can change and packets can arrive on different interfaces
|
||||
//m_endPoint->SetLocalAddress (Ipv4Address::GetAny());
|
||||
}
|
||||
// TCP SYN consumes one byte
|
||||
m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
|
||||
SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
|
||||
// This is the cloned endpoint
|
||||
NS_ASSERT (m_state == SYN_RCVD);
|
||||
m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
|
||||
if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
|
||||
{
|
||||
m_localAddress = ipv4->GetAddress (localIfIndex);
|
||||
m_endPoint->SetLocalAddress (m_localAddress);
|
||||
// Leave local addr in the portmap to any, as the path from
|
||||
// remote can change and packets can arrive on different interfaces
|
||||
//m_endPoint->SetLocalAddress (Ipv4Address::GetAny());
|
||||
}
|
||||
// TCP SYN consumes one byte
|
||||
m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
|
||||
SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
|
||||
break;
|
||||
case ACK_TX_1:
|
||||
NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action ACK_TX_1");
|
||||
@@ -790,7 +817,6 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
|
||||
NS_LOG_DEBUG ("TcpSocketImpl " << this << " ACK_TX_1" <<
|
||||
" nextRxSeq " << m_nextRxSequence);
|
||||
SendEmptyPacket (TcpHeader::ACK);
|
||||
m_rxWindowSize = tcpHeader.GetWindowSize ();
|
||||
if (tcpHeader.GetAckNumber () > m_highestRxAck)
|
||||
{
|
||||
m_highestRxAck = tcpHeader.GetAckNumber ();
|
||||
@@ -808,13 +834,17 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (tcpHeader.GetAckNumber () == m_highestRxAck &&
|
||||
tcpHeader.GetAckNumber () < m_nextTxSequence)
|
||||
if (tcpHeader.GetAckNumber () == m_highestRxAck)
|
||||
{
|
||||
DupAck (tcpHeader, ++m_dupAckCount);
|
||||
if (tcpHeader.GetAckNumber () < m_nextTxSequence)
|
||||
{
|
||||
DupAck (tcpHeader, ++m_dupAckCount);
|
||||
}
|
||||
NS_ASSERT(tcpHeader.GetAckNumber () <= m_nextTxSequence);
|
||||
//if the ack is precisely equal to the nextTxSequence
|
||||
break;
|
||||
}
|
||||
if (tcpHeader.GetAckNumber () > m_highestRxAck)
|
||||
if (tcpHeader.GetAckNumber () > m_highestRxAck)
|
||||
{
|
||||
m_dupAckCount = 0;
|
||||
}
|
||||
@@ -844,6 +874,7 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
|
||||
{
|
||||
NewRx (p, tcpHeader, fromAddress);
|
||||
}
|
||||
++m_nextRxSequence; //bump this to account for the FIN
|
||||
States_t saveState = m_state; // Used to see if app responds
|
||||
NS_LOG_LOGIC ("TcpSocketImpl " << this
|
||||
<< " peer close, state " << m_state);
|
||||
@@ -878,7 +909,7 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
|
||||
NotifyNewConnectionCreated (this, fromAddress);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return ProcessAction (a);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -928,7 +959,7 @@ bool TcpSocketImpl::SendPendingData (bool withAck)
|
||||
<< " highestRxAck " << m_highestRxAck
|
||||
<< " pd->Size " << m_pendingData->Size ()
|
||||
<< " pd->SFS " << m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence));
|
||||
|
||||
//XXX pd->Size is probably a bug, should be SizeFromSeq(...)
|
||||
if (w < m_segmentSize && m_pendingData->Size () > w)
|
||||
{
|
||||
break; // No more
|
||||
@@ -961,6 +992,7 @@ bool TcpSocketImpl::SendPendingData (bool withAck)
|
||||
header.SetAckNumber (m_nextRxSequence);
|
||||
header.SetSourcePort (m_endPoint->GetLocalPort());
|
||||
header.SetDestinationPort (m_remotePort);
|
||||
header.SetWindowSize (AdvertisedWindowSize());
|
||||
if (m_shutdownSend)
|
||||
{
|
||||
m_errno = ERROR_SHUTDOWN;
|
||||
@@ -971,7 +1003,7 @@ bool TcpSocketImpl::SendPendingData (bool withAck)
|
||||
if (m_retxEvent.IsExpired () ) //go ahead and schedule the retransmit
|
||||
{
|
||||
Time rto = m_rtt->RetransmitTimeout ();
|
||||
NS_LOG_LOGIC ("SendPendingData Schedule retransmission timeout at time " <<
|
||||
NS_LOG_LOGIC (this<<" SendPendingData Schedule ReTxTimeout at time " <<
|
||||
Simulator::Now ().GetSeconds () << " to expire at time " <<
|
||||
(Simulator::Now () + rto).GetSeconds () );
|
||||
m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this);
|
||||
@@ -1024,6 +1056,17 @@ uint32_t TcpSocketImpl::AvailableWindow ()
|
||||
return (win - unack); // Amount of window space available
|
||||
}
|
||||
|
||||
uint32_t TcpSocketImpl::RxBufferFreeSpace()
|
||||
{
|
||||
return m_rxBufMaxSize - m_rxBufSize;
|
||||
}
|
||||
|
||||
uint16_t TcpSocketImpl::AdvertisedWindowSize()
|
||||
{
|
||||
uint32_t max = 0xffff;
|
||||
return std::min(RxBufferFreeSpace(), max);
|
||||
}
|
||||
|
||||
void TcpSocketImpl::NewRx (Ptr<Packet> p,
|
||||
const TcpHeader& tcpHeader,
|
||||
const Address& fromAddress)
|
||||
@@ -1039,9 +1082,20 @@ void TcpSocketImpl::NewRx (Ptr<Packet> p,
|
||||
" ack " << tcpHeader.GetAckNumber() <<
|
||||
" p.size is " << p->GetSize());
|
||||
States_t origState = m_state;
|
||||
if (RxBufferFreeSpace() < p->GetSize())
|
||||
{ //if not enough room, fragment
|
||||
p = p->CreateFragment(0, RxBufferFreeSpace());
|
||||
}
|
||||
//XXX
|
||||
//fragmenting here MIGHT not be the right thing to do, since possibly we trim
|
||||
//the front and back off the packet below if it isn't all new data, so the
|
||||
//check against RxBufferFreeSpace and fragmentation should ideally occur
|
||||
//just before insertion into m_bufferedData, but this strategy is more
|
||||
//agressive in rejecting oversized packets and still gives acceptable TCP
|
||||
uint32_t s = p->GetSize (); // Size of associated data
|
||||
if (s == 0)
|
||||
{// Nothing to do if no associated data
|
||||
{//if there is no data or no rx buffer space, just ack anyway
|
||||
SendEmptyPacket (TcpHeader::ACK);
|
||||
return;
|
||||
}
|
||||
// Log sequence received if enabled
|
||||
@@ -1074,14 +1128,12 @@ void TcpSocketImpl::NewRx (Ptr<Packet> p,
|
||||
//buffer this, it'll be read by call to Recv
|
||||
UnAckData_t::iterator i =
|
||||
m_bufferedData.find (tcpHeader.GetSequenceNumber () );
|
||||
if (i != m_bufferedData.end () ) //we found it already in the buffer
|
||||
{
|
||||
i->second = 0; // relase reference to already buffered
|
||||
}
|
||||
// Save for later delivery
|
||||
m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;
|
||||
NS_ASSERT(i == m_bufferedData.end ()); //no way it should have been found
|
||||
// Save for later delivery if there is room
|
||||
m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;
|
||||
m_rxAvailable += p->GetSize ();
|
||||
RxBufFinishInsert (tcpHeader.GetSequenceNumber ());
|
||||
m_rxBufSize += p->GetSize ();
|
||||
NotifyDataRecv ();
|
||||
if (m_closeNotified)
|
||||
{
|
||||
@@ -1181,6 +1233,7 @@ void TcpSocketImpl::NewRx (Ptr<Packet> p,
|
||||
// Save for later delivery
|
||||
m_bufferedData[start] = p;
|
||||
m_rxAvailable += p->GetSize ();
|
||||
m_rxBufSize += p->GetSize();
|
||||
RxBufFinishInsert(start);
|
||||
NotifyDataRecv ();
|
||||
}
|
||||
@@ -1248,13 +1301,31 @@ void TcpSocketImpl::CommonNewAck (SequenceNumber ack, bool skipTimer)
|
||||
//DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl));
|
||||
if (!skipTimer)
|
||||
{
|
||||
m_retxEvent.Cancel ();
|
||||
NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at "
|
||||
<< (Simulator::Now () +
|
||||
Simulator::GetDelayLeft (m_retxEvent)).GetSeconds());
|
||||
m_retxEvent.Cancel ();
|
||||
//On recieving a "New" ack we restart retransmission timer .. RFC 2988
|
||||
Time rto = m_rtt->RetransmitTimeout ();
|
||||
NS_LOG_LOGIC ("Schedule retransmission timeout at time "
|
||||
NS_LOG_LOGIC (this<<" Schedule ReTxTimeout at time "
|
||||
<< Simulator::Now ().GetSeconds () << " to expire at time "
|
||||
<< (Simulator::Now () + rto).GetSeconds ());
|
||||
m_retxEvent = Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this);
|
||||
m_retxEvent =
|
||||
Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this);
|
||||
}
|
||||
if (m_rxWindowSize == 0 && m_persistEvent.IsExpired ()) //zerowindow
|
||||
{
|
||||
NS_LOG_LOGIC (this<<"Enter zerowindow persist state");
|
||||
NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at "
|
||||
<< (Simulator::Now () +
|
||||
Simulator::GetDelayLeft (m_retxEvent)).GetSeconds());
|
||||
m_retxEvent.Cancel ();
|
||||
NS_LOG_LOGIC ("Schedule persist timeout at time "
|
||||
<<Simulator::Now ().GetSeconds () << " to expire at time "
|
||||
<< (Simulator::Now () + m_persistTime).GetSeconds());
|
||||
m_persistEvent =
|
||||
Simulator::Schedule (m_persistTime, &TcpSocketImpl::PersistTimeout, this);
|
||||
NS_ASSERT (m_persistTime == Simulator::GetDelayLeft (m_persistEvent));
|
||||
}
|
||||
NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack
|
||||
<< " numberAck " << (ack - m_highestRxAck)); // Number bytes ack'ed
|
||||
@@ -1276,6 +1347,9 @@ void TcpSocketImpl::CommonNewAck (SequenceNumber ack, bool skipTimer)
|
||||
delete m_pendingData;
|
||||
m_pendingData = 0;
|
||||
// Insure no re-tx timer
|
||||
NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at "
|
||||
<< (Simulator::Now () +
|
||||
Simulator::GetDelayLeft (m_retxEvent)).GetSeconds());
|
||||
m_retxEvent.Cancel ();
|
||||
}
|
||||
}
|
||||
@@ -1341,6 +1415,7 @@ void TcpSocketImpl::DupAck (const TcpHeader& t, uint32_t count)
|
||||
void TcpSocketImpl::ReTxTimeout ()
|
||||
{ // Retransmit timeout
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC (this<<" ReTxTimeout Expired at time "<<Simulator::Now ().GetSeconds());
|
||||
m_ssThresh = Window () / 2; // Per RFC2581
|
||||
m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
|
||||
// Set cWnd to segSize on timeout, per rfc2581
|
||||
@@ -1365,6 +1440,31 @@ void TcpSocketImpl::LastAckTimeout ()
|
||||
}
|
||||
}
|
||||
|
||||
void TcpSocketImpl::PersistTimeout ()
|
||||
{
|
||||
NS_LOG_LOGIC ("PersistTimeout expired at "<<Simulator::Now ().GetSeconds ());
|
||||
m_persistTime = Scalar(2)*m_persistTime;
|
||||
m_persistTime = std::min(Seconds(60),m_persistTime); //maxes out at 60
|
||||
//the persist timeout sends exactly one byte probes
|
||||
//this is explicit in stevens, and kind of in rfc793 p42, rfc1122 sec4.2.2.17
|
||||
Ptr<Packet> p =
|
||||
m_pendingData->CopyFromSeq(1,m_firstPendingSequence,m_nextTxSequence);
|
||||
TcpHeader tcpHeader;
|
||||
tcpHeader.SetSequenceNumber (m_nextTxSequence);
|
||||
tcpHeader.SetAckNumber (m_nextRxSequence);
|
||||
tcpHeader.SetSourcePort (m_endPoint->GetLocalPort());
|
||||
tcpHeader.SetDestinationPort (m_remotePort);
|
||||
tcpHeader.SetWindowSize (AdvertisedWindowSize());
|
||||
|
||||
m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (),
|
||||
m_remoteAddress);
|
||||
NS_LOG_LOGIC ("Schedule persist timeout at time "
|
||||
<<Simulator::Now ().GetSeconds () << " to expire at time "
|
||||
<< (Simulator::Now () + m_persistTime).GetSeconds());
|
||||
m_persistEvent =
|
||||
Simulator::Schedule (m_persistTime, &TcpSocketImpl::PersistTimeout, this);
|
||||
}
|
||||
|
||||
void TcpSocketImpl::Retransmit ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
@@ -1390,9 +1490,10 @@ void TcpSocketImpl::Retransmit ()
|
||||
}
|
||||
return;
|
||||
}
|
||||
NS_ASSERT(m_nextTxSequence == m_highestRxAck);
|
||||
Ptr<Packet> p = m_pendingData->CopyFromSeq (m_segmentSize,
|
||||
m_firstPendingSequence,
|
||||
m_highestRxAck);
|
||||
m_nextTxSequence);
|
||||
// Calculate remaining data for COE check
|
||||
uint32_t remainingData = m_pendingData->SizeFromSeq (
|
||||
m_firstPendingSequence,
|
||||
@@ -1406,7 +1507,7 @@ void TcpSocketImpl::Retransmit ()
|
||||
if (m_retxEvent.IsExpired () )
|
||||
{
|
||||
Time rto = m_rtt->RetransmitTimeout ();
|
||||
NS_LOG_LOGIC ("Schedule retransmission timeout at time "
|
||||
NS_LOG_LOGIC (this<<" Schedule ReTxTimeout at time "
|
||||
<< Simulator::Now ().GetSeconds () << " to expire at time "
|
||||
<< (Simulator::Now () + rto).GetSeconds ());
|
||||
m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this);
|
||||
@@ -1419,7 +1520,7 @@ void TcpSocketImpl::Retransmit ()
|
||||
tcpHeader.SetSourcePort (m_endPoint->GetLocalPort());
|
||||
tcpHeader.SetDestinationPort (m_remotePort);
|
||||
tcpHeader.SetFlags (flags);
|
||||
tcpHeader.SetWindowSize (m_advertisedWindowSize);
|
||||
tcpHeader.SetWindowSize (AdvertisedWindowSize());
|
||||
|
||||
m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (),
|
||||
m_remoteAddress);
|
||||
@@ -1440,13 +1541,13 @@ TcpSocketImpl::GetSndBufSize (void) const
|
||||
void
|
||||
TcpSocketImpl::SetRcvBufSize (uint32_t size)
|
||||
{
|
||||
m_rcvBufSize = size;
|
||||
m_rxBufMaxSize = size;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpSocketImpl::GetRcvBufSize (void) const
|
||||
{
|
||||
return m_rcvBufSize;
|
||||
return m_rxBufMaxSize;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1461,18 +1562,6 @@ TcpSocketImpl::GetSegSize (void) const
|
||||
return m_segmentSize;
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketImpl::SetAdvWin (uint32_t window)
|
||||
{
|
||||
m_advertisedWindowSize = window;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpSocketImpl::GetAdvWin (void) const
|
||||
{
|
||||
return m_advertisedWindowSize;
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketImpl::SetSSThresh (uint32_t threshold)
|
||||
{
|
||||
@@ -1556,6 +1645,7 @@ TcpSocketImpl::GetDelAckMaxCount (void) const
|
||||
#include "ns3/simple-channel.h"
|
||||
#include "ns3/simple-net-device.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/config.h"
|
||||
#include "internet-stack.h"
|
||||
#include <string>
|
||||
|
||||
@@ -1567,20 +1657,34 @@ class TcpSocketImplTest: public Test
|
||||
TcpSocketImplTest ();
|
||||
virtual bool RunTests (void);
|
||||
private:
|
||||
void Test1 (void); //send string "Hello world" server->client
|
||||
void Test2 (uint32_t payloadSize);
|
||||
Ptr<Node> CreateInternetNode ();
|
||||
Ptr<SimpleNetDevice> AddSimpleNetDevice (Ptr<Node>,const char*,const char*);
|
||||
|
||||
//test 1, which sends string "Hello world" server->client
|
||||
void Test1 (void);
|
||||
void Test1_HandleConnectionCreated (Ptr<Socket>, const Address &);
|
||||
void Test1_HandleRecv (Ptr<Socket> sock);
|
||||
|
||||
//test 2, which sends a number of bytes server->client
|
||||
void Test2 (uint32_t payloadSize);
|
||||
void Test2_HandleConnectionCreated (Ptr<Socket>, const Address &);
|
||||
void Test2_HandleRecv (Ptr<Socket> sock);
|
||||
uint32_t test2_payloadSize;
|
||||
|
||||
//test 3, which makes sure the rx buffer is finite
|
||||
void Test3 (uint32_t payloadSize);
|
||||
void Test3_HandleConnectionCreated (Ptr<Socket>, const Address &);
|
||||
void Test3_HandleRecv (Ptr<Socket> sock);
|
||||
uint32_t test3_payloadSize;
|
||||
|
||||
//helpers to make topology construction easier
|
||||
Ptr<Node> CreateInternetNode ();
|
||||
Ptr<SimpleNetDevice> AddSimpleNetDevice (Ptr<Node>,const char*,const char*);
|
||||
void SetupDefaultSim ();
|
||||
|
||||
//reset all of the below state for another run
|
||||
void Reset ();
|
||||
|
||||
|
||||
//all of the state this class needs; basically both ends of the connection,
|
||||
//and this test kind of acts as an single application running on both nodes
|
||||
//simultaneously
|
||||
Ptr<Node> node0;
|
||||
Ptr<Node> node1;
|
||||
Ptr<SimpleNetDevice> dev0;
|
||||
@@ -1591,9 +1695,9 @@ class TcpSocketImplTest: public Test
|
||||
Ptr<Socket> sock1;
|
||||
uint32_t rxBytes0;
|
||||
uint32_t rxBytes1;
|
||||
|
||||
|
||||
uint8_t* rxPayload;
|
||||
|
||||
|
||||
bool result;
|
||||
};
|
||||
|
||||
@@ -1610,118 +1714,34 @@ bool
|
||||
TcpSocketImplTest::RunTests (void)
|
||||
{
|
||||
Test1();
|
||||
if (!result) return false;
|
||||
Test2(600);
|
||||
if (!result) return false;
|
||||
Test3(20000);
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//test 1-----------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
TcpSocketImplTest::Test1 ()
|
||||
{
|
||||
const char* netmask = "255.255.255.0";
|
||||
const char* ipaddr0 = "192.168.1.1";
|
||||
const char* ipaddr1 = "192.168.1.2";
|
||||
node0 = CreateInternetNode ();
|
||||
node1 = CreateInternetNode ();
|
||||
dev0 = AddSimpleNetDevice (node0, ipaddr0, netmask);
|
||||
dev1 = AddSimpleNetDevice (node1, ipaddr1, netmask);
|
||||
|
||||
channel = CreateObject<SimpleChannel> ();
|
||||
dev0->SetChannel (channel);
|
||||
dev1->SetChannel (channel);
|
||||
|
||||
Ptr<SocketFactory> sockFactory0 = node0->GetObject<TcpSocketFactory> ();
|
||||
Ptr<SocketFactory> sockFactory1 = node1->GetObject<TcpSocketFactory> ();
|
||||
|
||||
listeningSock = sockFactory0->CreateSocket();
|
||||
sock1 = sockFactory1->CreateSocket();
|
||||
|
||||
uint16_t port = 50000;
|
||||
InetSocketAddress serverlocaladdr (Ipv4Address::GetAny(), port);
|
||||
InetSocketAddress serverremoteaddr (Ipv4Address(ipaddr0), port);
|
||||
|
||||
listeningSock->Bind(serverlocaladdr);
|
||||
listeningSock->Listen (0);
|
||||
SetupDefaultSim ();
|
||||
listeningSock->SetAcceptCallback
|
||||
(MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
|
||||
MakeCallback(&TcpSocketImplTest::Test1_HandleConnectionCreated,this));
|
||||
|
||||
sock1->Connect(serverremoteaddr);
|
||||
(MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
|
||||
MakeCallback(&TcpSocketImplTest::Test1_HandleConnectionCreated,this));
|
||||
sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test1_HandleRecv, this));
|
||||
|
||||
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
|
||||
result = result && (rxBytes1 == 13);
|
||||
result = result && (strcmp((const char*) rxPayload,"Hello World!") == 0);
|
||||
|
||||
|
||||
Reset ();
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketImplTest::Test2 (uint32_t payloadSize)
|
||||
{
|
||||
test2_payloadSize = payloadSize;
|
||||
const char* netmask = "255.255.255.0";
|
||||
const char* ipaddr0 = "192.168.1.1";
|
||||
const char* ipaddr1 = "192.168.1.2";
|
||||
node0 = CreateInternetNode ();
|
||||
node1 = CreateInternetNode ();
|
||||
dev0 = AddSimpleNetDevice (node0, ipaddr0, netmask);
|
||||
dev1 = AddSimpleNetDevice (node1, ipaddr1, netmask);
|
||||
|
||||
channel = CreateObject<SimpleChannel> ();
|
||||
dev0->SetChannel (channel);
|
||||
dev1->SetChannel (channel);
|
||||
|
||||
Ptr<SocketFactory> sockFactory0 = node0->GetObject<TcpSocketFactory> ();
|
||||
Ptr<SocketFactory> sockFactory1 = node1->GetObject<TcpSocketFactory> ();
|
||||
|
||||
listeningSock = sockFactory0->CreateSocket();
|
||||
sock1 = sockFactory1->CreateSocket();
|
||||
|
||||
uint16_t port = 50000;
|
||||
InetSocketAddress serverlocaladdr (Ipv4Address::GetAny(), port);
|
||||
InetSocketAddress serverremoteaddr (Ipv4Address(ipaddr0), port);
|
||||
|
||||
listeningSock->Bind(serverlocaladdr);
|
||||
listeningSock->Listen (0);
|
||||
listeningSock->SetAcceptCallback
|
||||
(MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
|
||||
MakeCallback(&TcpSocketImplTest::Test2_HandleConnectionCreated,this));
|
||||
|
||||
sock1->Connect(serverremoteaddr);
|
||||
sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test2_HandleRecv, this));
|
||||
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
result = result && (rxBytes1 == test2_payloadSize);
|
||||
|
||||
Reset ();
|
||||
}
|
||||
|
||||
Ptr<Node>
|
||||
TcpSocketImplTest::CreateInternetNode ()
|
||||
{
|
||||
Ptr<Node> node = CreateObject<Node> ();
|
||||
AddInternetStack (node);
|
||||
return node;
|
||||
}
|
||||
|
||||
Ptr<SimpleNetDevice>
|
||||
TcpSocketImplTest::AddSimpleNetDevice (Ptr<Node> node, const char* ipaddr, const char* netmask)
|
||||
{
|
||||
Ptr<SimpleNetDevice> dev = CreateObject<SimpleNetDevice> ();
|
||||
dev->SetAddress (Mac48Address::Allocate ());
|
||||
node->AddDevice (dev);
|
||||
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
|
||||
uint32_t ndid = ipv4->AddInterface (dev);
|
||||
ipv4->SetAddress (ndid, Ipv4Address (ipaddr));
|
||||
ipv4->SetNetworkMask (ndid, Ipv4Mask (netmask));
|
||||
ipv4->SetUp (ndid);
|
||||
return dev;
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketImplTest::Test1_HandleConnectionCreated (Ptr<Socket> s, const Address & addr)
|
||||
{
|
||||
@@ -1753,6 +1773,27 @@ TcpSocketImplTest::Test1_HandleRecv (Ptr<Socket> sock)
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//test 2-----------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
TcpSocketImplTest::Test2 (uint32_t payloadSize)
|
||||
{
|
||||
test2_payloadSize = payloadSize;
|
||||
SetupDefaultSim ();
|
||||
listeningSock->SetAcceptCallback
|
||||
(MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
|
||||
MakeCallback(&TcpSocketImplTest::Test2_HandleConnectionCreated,this));
|
||||
sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test2_HandleRecv, this));
|
||||
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
result = result && (rxBytes1 == test2_payloadSize);
|
||||
|
||||
Reset ();
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketImplTest::Test2_HandleConnectionCreated (Ptr<Socket> s, const Address & addr)
|
||||
{
|
||||
@@ -1777,10 +1818,108 @@ TcpSocketImplTest::Test2_HandleRecv (Ptr<Socket> sock)
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Recv from unknown socket "<<sock);
|
||||
NS_FATAL_ERROR ("Not supposed to be back traffic in test 2..."<<sock);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//test 3-----------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
TcpSocketImplTest::Test3 (uint32_t payloadSize)
|
||||
{
|
||||
Config::SetDefault ("ns3::TcpSocket::RcvBufSize", UintegerValue (10000));
|
||||
test3_payloadSize = payloadSize;
|
||||
SetupDefaultSim ();
|
||||
listeningSock->SetAcceptCallback
|
||||
(MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
|
||||
MakeCallback(&TcpSocketImplTest::Test3_HandleConnectionCreated,this));
|
||||
sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test3_HandleRecv, this));
|
||||
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
result = result && (rxBytes1 == test3_payloadSize);
|
||||
|
||||
Reset();
|
||||
}
|
||||
void
|
||||
TcpSocketImplTest::Test3_HandleConnectionCreated (Ptr<Socket> s, const Address &)
|
||||
{
|
||||
NS_ASSERT(s != listeningSock);
|
||||
NS_ASSERT(sock0 == 0);
|
||||
sock0 = s;
|
||||
Ptr<Packet> p = Create<Packet> (test3_payloadSize);
|
||||
sock0->Send(p);
|
||||
}
|
||||
void
|
||||
TcpSocketImplTest::Test3_HandleRecv (Ptr<Socket> sock)
|
||||
{
|
||||
NS_ASSERT_MSG (sock == sock1, "Not supposed to be back traffic in test 3... ");
|
||||
if(sock->GetRxAvailable() >= 10000 ) //perform batch reads every 10000 bytes
|
||||
{
|
||||
Ptr<Packet> p = sock->Recv();
|
||||
uint32_t sz = p->GetSize();
|
||||
rxBytes1 += sz;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//helpers----------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
Ptr<Node>
|
||||
TcpSocketImplTest::CreateInternetNode ()
|
||||
{
|
||||
Ptr<Node> node = CreateObject<Node> ();
|
||||
AddInternetStack (node);
|
||||
return node;
|
||||
}
|
||||
|
||||
Ptr<SimpleNetDevice>
|
||||
TcpSocketImplTest::AddSimpleNetDevice (Ptr<Node> node, const char* ipaddr, const char* netmask)
|
||||
{
|
||||
Ptr<SimpleNetDevice> dev = CreateObject<SimpleNetDevice> ();
|
||||
dev->SetAddress (Mac48Address::Allocate ());
|
||||
node->AddDevice (dev);
|
||||
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
|
||||
uint32_t ndid = ipv4->AddInterface (dev);
|
||||
ipv4->SetAddress (ndid, Ipv4Address (ipaddr));
|
||||
ipv4->SetNetworkMask (ndid, Ipv4Mask (netmask));
|
||||
ipv4->SetUp (ndid);
|
||||
return dev;
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketImplTest::SetupDefaultSim ()
|
||||
{
|
||||
const char* netmask = "255.255.255.0";
|
||||
const char* ipaddr0 = "192.168.1.1";
|
||||
const char* ipaddr1 = "192.168.1.2";
|
||||
node0 = CreateInternetNode ();
|
||||
node1 = CreateInternetNode ();
|
||||
dev0 = AddSimpleNetDevice (node0, ipaddr0, netmask);
|
||||
dev1 = AddSimpleNetDevice (node1, ipaddr1, netmask);
|
||||
|
||||
channel = CreateObject<SimpleChannel> ();
|
||||
dev0->SetChannel (channel);
|
||||
dev1->SetChannel (channel);
|
||||
|
||||
Ptr<SocketFactory> sockFactory0 = node0->GetObject<TcpSocketFactory> ();
|
||||
Ptr<SocketFactory> sockFactory1 = node1->GetObject<TcpSocketFactory> ();
|
||||
|
||||
listeningSock = sockFactory0->CreateSocket();
|
||||
sock1 = sockFactory1->CreateSocket();
|
||||
|
||||
uint16_t port = 50000;
|
||||
InetSocketAddress serverlocaladdr (Ipv4Address::GetAny(), port);
|
||||
InetSocketAddress serverremoteaddr (Ipv4Address(ipaddr0), port);
|
||||
|
||||
listeningSock->Bind(serverlocaladdr);
|
||||
listeningSock->Listen (0);
|
||||
|
||||
sock1->Connect(serverremoteaddr);
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketImplTest::Reset ()
|
||||
{
|
||||
|
||||
@@ -121,6 +121,10 @@ private:
|
||||
virtual uint32_t Window(); // Return window size (integer)
|
||||
virtual uint32_t AvailableWindow();// Return unfilled portion of window
|
||||
|
||||
//methods for Rx buffer management
|
||||
uint32_t RxBufferFreeSpace();
|
||||
uint16_t AdvertisedWindowSize();
|
||||
|
||||
// Manage data tx/rx
|
||||
void NewRx (Ptr<Packet>, const TcpHeader&, const Address&);
|
||||
void RxBufFinishInsert (SequenceNumber);
|
||||
@@ -132,6 +136,7 @@ private:
|
||||
void ReTxTimeout ();
|
||||
void DelAckTimeout ();
|
||||
void LastAckTimeout ();
|
||||
void PersistTimeout ();
|
||||
void Retransmit ();
|
||||
void CommonNewAck (SequenceNumber seq, bool skipTimer = false);
|
||||
|
||||
@@ -142,8 +147,6 @@ private:
|
||||
virtual uint32_t GetRcvBufSize (void) const;
|
||||
virtual void SetSegSize (uint32_t size);
|
||||
virtual uint32_t GetSegSize (void) const;
|
||||
virtual void SetAdvWin (uint32_t window);
|
||||
virtual uint32_t GetAdvWin (void) const;
|
||||
virtual void SetSSThresh (uint32_t threshold);
|
||||
virtual uint32_t GetSSThresh (void) const;
|
||||
virtual void SetInitialCwnd (uint32_t cwnd);
|
||||
@@ -195,23 +198,33 @@ private:
|
||||
SequenceNumber m_lastRxAck;
|
||||
|
||||
//sequence info, reciever side
|
||||
SequenceNumber m_nextRxSequence;
|
||||
SequenceNumber m_nextRxSequence; //next expected sequence
|
||||
|
||||
//Rx buffer
|
||||
UnAckData_t m_bufferedData; //buffer which sorts out of sequence data
|
||||
//Rx buffer state
|
||||
uint32_t m_rxAvailable; // amount of data available for reading through Recv
|
||||
uint32_t m_rxBufSize; //size in bytes of the data in the rx buf
|
||||
//note that these two are not the same: rxAvailbale is the number of
|
||||
//contiguous sequenced bytes that can be read, rxBufSize is the TOTAL size
|
||||
//including out of sequence data, such that m_rxAvailable <= m_rxBufSize
|
||||
|
||||
//history data
|
||||
//this is the incoming data buffer which sorts out of sequence data
|
||||
UnAckData_t m_bufferedData;
|
||||
//this is kind of the tx buffer
|
||||
PendingData* m_pendingData;
|
||||
SequenceNumber m_firstPendingSequence;
|
||||
|
||||
// Window management
|
||||
uint32_t m_segmentSize; //SegmentSize
|
||||
uint32_t m_rxWindowSize;
|
||||
uint32_t m_advertisedWindowSize; //Window to advertise
|
||||
uint32_t m_rxWindowSize; //Flow control window
|
||||
TracedValue<uint32_t> m_cWnd; //Congestion window
|
||||
uint32_t m_ssThresh; //Slow Start Threshold
|
||||
uint32_t m_initialCWnd; //Initial cWnd value
|
||||
|
||||
//persist timer management
|
||||
Time m_persistTime;
|
||||
EventId m_persistEvent;
|
||||
|
||||
|
||||
// Round trip time estimation
|
||||
Ptr<RttEstimator> m_rtt;
|
||||
Time m_lastMeasuredRtt;
|
||||
@@ -220,12 +233,9 @@ private:
|
||||
Time m_cnTimeout;
|
||||
uint32_t m_cnCount;
|
||||
|
||||
// Temporary queue for delivering data to application
|
||||
uint32_t m_rxAvailable;
|
||||
|
||||
// Attributes
|
||||
uint32_t m_sndBufSize; // buffer limit for the outgoing queue
|
||||
uint32_t m_rcvBufSize; // maximum receive socket buffer size
|
||||
uint32_t m_rxBufMaxSize; // maximum receive socket buffer size
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
@@ -63,21 +63,21 @@ typedef enum {
|
||||
typedef enum {
|
||||
NO_ACT, // 0
|
||||
ACK_TX, // 1
|
||||
ACK_TX_1, // ACK response to syn
|
||||
RST_TX, // 2
|
||||
SYN_TX, // 3
|
||||
SYN_ACK_TX, // 4
|
||||
FIN_TX, // 5
|
||||
FIN_ACK_TX, // 6
|
||||
NEW_ACK, // 7
|
||||
NEW_SEQ_RX, // 8
|
||||
RETX, // 9
|
||||
TX_DATA, // 10
|
||||
PEER_CLOSE, // 11
|
||||
APP_CLOSED, // 12
|
||||
CANCEL_TM, // 13
|
||||
APP_NOTIFY, // 14 - Notify app that connection failed
|
||||
SERV_NOTIFY, // 15 - Notify server tcp that connection completed
|
||||
ACK_TX_1, // 2 - ACK response to syn
|
||||
RST_TX, // 3
|
||||
SYN_TX, // 4
|
||||
SYN_ACK_TX, // 5
|
||||
FIN_TX, // 6
|
||||
FIN_ACK_TX, // 7
|
||||
NEW_ACK, // 8
|
||||
NEW_SEQ_RX, // 9
|
||||
RETX, // 10
|
||||
TX_DATA, // 11
|
||||
PEER_CLOSE, // 12
|
||||
APP_CLOSED, // 13
|
||||
CANCEL_TM, // 14
|
||||
APP_NOTIFY, // 15 - Notify app that connection failed
|
||||
SERV_NOTIFY, // 16 - Notify server tcp that connection completed
|
||||
LAST_ACTION } Actions_t;
|
||||
|
||||
class SA // State/Action pair
|
||||
|
||||
@@ -55,12 +55,6 @@ TcpSocket::GetTypeId (void)
|
||||
MakeUintegerAccessor (&TcpSocket::GetSegSize,
|
||||
&TcpSocket::SetSegSize),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("AdvertisedWindowSize",
|
||||
"TCP advertised window size (bytes)",
|
||||
UintegerValue (0xffff),
|
||||
MakeUintegerAccessor (&TcpSocket::GetAdvWin,
|
||||
&TcpSocket::SetAdvWin),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("SlowStartThreshold",
|
||||
"TCP slow start threshold (bytes)",
|
||||
UintegerValue (0xffff),
|
||||
|
||||
@@ -59,8 +59,6 @@ private:
|
||||
virtual uint32_t GetRcvBufSize (void) const = 0;
|
||||
virtual void SetSegSize (uint32_t size) = 0;
|
||||
virtual uint32_t GetSegSize (void) const = 0;
|
||||
virtual void SetAdvWin (uint32_t window) = 0;
|
||||
virtual uint32_t GetAdvWin (void) const = 0;
|
||||
virtual void SetSSThresh (uint32_t threshold) = 0;
|
||||
virtual uint32_t GetSSThresh (void) const = 0;
|
||||
virtual void SetInitialCwnd (uint32_t count) = 0;
|
||||
|
||||
Reference in New Issue
Block a user