--- a/CHANGES.html Mon Sep 08 12:19:46 2008 +0100
+++ b/CHANGES.html Mon Sep 08 12:35:08 2008 +0100
@@ -217,6 +217,63 @@
<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>
--- a/examples/tcp-errors.cc Mon Sep 08 12:19:46 2008 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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 ();
-}
--- a/examples/tcp-large-transfer.cc Mon Sep 08 12:19:46 2008 +0100
+++ b/examples/tcp-large-transfer.cc Mon Sep 08 12:35:08 2008 +0100
@@ -132,6 +132,7 @@
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
--- a/examples/wscript Mon Sep 08 12:19:46 2008 +0100
+++ b/examples/wscript Mon Sep 08 12:35:08 2008 +0100
@@ -60,10 +60,6 @@
['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'
--- a/src/internet-stack/pending-data.cc Mon Sep 08 12:19:46 2008 +0100
+++ b/src/internet-stack/pending-data.cc Mon Sep 08 12:35:08 2008 +0100
@@ -131,7 +131,7 @@
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
--- a/src/internet-stack/tcp-socket-impl.cc Mon Sep 08 12:19:46 2008 +0100
+++ b/src/internet-stack/tcp-socket-impl.cc Mon Sep 08 12:35:08 2008 +0100
@@ -76,10 +76,13 @@
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 @@
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 @@
m_node = node;
// Initialize some variables
m_cWnd = m_initialCWnd * m_segmentSize;
- m_rxWindowSize = m_advertisedWindowSize;
}
void
@@ -212,6 +215,9 @@
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 @@
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 @@
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 @@
}
}
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
{
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 @@
NotifyNewConnectionCreated (this, fromAddress);
break;
default:
- break;
+ return ProcessAction (a);
}
return true;
}
@@ -928,7 +959,7 @@
<< " 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 @@
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 @@
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 @@
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 @@
" 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 @@
//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 @@
// Save for later delivery
m_bufferedData[start] = p;
m_rxAvailable += p->GetSize ();
+ m_rxBufSize += p->GetSize();
RxBufFinishInsert(start);
NotifyDataRecv ();
}
@@ -1248,13 +1301,31 @@
//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 @@
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::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::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 @@
}
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 @@
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 @@
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 @@
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
@@ -1462,18 +1563,6 @@
}
void
-TcpSocketImpl::SetAdvWin (uint32_t window)
-{
- m_advertisedWindowSize = window;
-}
-
-uint32_t
-TcpSocketImpl::GetAdvWin (void) const
-{
- return m_advertisedWindowSize;
-}
-
-void
TcpSocketImpl::SetSSThresh (uint32_t threshold)
{
m_ssThresh = threshold;
@@ -1556,6 +1645,7 @@
#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 @@
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 @@
Ptr<Socket> sock1;
uint32_t rxBytes0;
uint32_t rxBytes1;
-
+
uint8_t* rxPayload;
-
+
bool result;
};
@@ -1610,119 +1714,35 @@
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)
{
NS_ASSERT(s != listeningSock);
@@ -1753,6 +1773,27 @@
}
}
+//-----------------------------------------------------------------------------
+//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 @@
}
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 ()
{
--- a/src/internet-stack/tcp-socket-impl.h Mon Sep 08 12:19:46 2008 +0100
+++ b/src/internet-stack/tcp-socket-impl.h Mon Sep 08 12:35:08 2008 +0100
@@ -121,6 +121,10 @@
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 @@
void ReTxTimeout ();
void DelAckTimeout ();
void LastAckTimeout ();
+ void PersistTimeout ();
void Retransmit ();
void CommonNewAck (SequenceNumber seq, bool skipTimer = false);
@@ -142,8 +147,6 @@
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 @@
SequenceNumber m_lastRxAck;
//sequence info, reciever side
- SequenceNumber m_nextRxSequence;
+ SequenceNumber m_nextRxSequence; //next expected sequence
- //history data
- //this is the incoming data buffer which sorts out of sequence data
- UnAckData_t m_bufferedData;
+ //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
+
//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 @@
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
--- a/src/internet-stack/tcp-typedefs.h Mon Sep 08 12:19:46 2008 +0100
+++ b/src/internet-stack/tcp-typedefs.h Mon Sep 08 12:35:08 2008 +0100
@@ -63,21 +63,21 @@
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
--- a/src/node/tcp-socket.cc Mon Sep 08 12:19:46 2008 +0100
+++ b/src/node/tcp-socket.cc Mon Sep 08 12:35:08 2008 +0100
@@ -55,12 +55,6 @@
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),
--- a/src/node/tcp-socket.h Mon Sep 08 12:19:46 2008 +0100
+++ b/src/node/tcp-socket.h Mon Sep 08 12:35:08 2008 +0100
@@ -59,8 +59,6 @@
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;