merge new TCP code

This commit is contained in:
Josh Pelkey
2010-12-17 13:57:22 -05:00
parent a650f91b57
commit da85b34487
35 changed files with 4397 additions and 2548 deletions

View File

@@ -0,0 +1,292 @@
/* -*- 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
//
// 8Mb/s, 0.1ms 0.8Mb/s, 100ms
// s1-----------------r1-----------------k1
//
// Example corresponding to simulations in the paper "Simulation-based
// Comparisons of Tahoe, Reno, and SACK TCP"
//
// To look at the time-sequence plots corresponding to the packet traces,
// the tcptrace tool (www.tcptrace.org) with the -S option can produce
// xplot plots (a2b.xpl, b2a.xpl) which can be viewed using xplot
//
// - Tracing of queues and packet receptions to file
// "tcp-loss-response.tr
// - pcap traces also generated in the following files
// "tcp-loss-response-s1-0.pcap" and "tcp-loss-response-k1-0.pcap"
//
// Usage (e.g.): ./waf --run tcp-loss-response
//
#include <ctype.h>
#include <iostream>
#include <iomanip>
#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/simulator-module.h"
#include "ns3/ipv4-global-routing-helper.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("TcpLossResponse");
// The number of bytes to send in this simulation.
static const uint32_t totalTxBytes = 200000;
static uint32_t currentTxBytes = 0;
// Perform series of 26*40=1040 byte writes (this is a multiple of 26 since
// we want to detect data splicing in the output stream)
static const uint32_t writeSize = 1040;
uint8_t data[writeSize];
// Need to invoke Socket::Close() on sender?
bool needToClose = true;
// These are for starting the writing process, and handling the sending
// socket's notification upcalls (events). These two together more or less
// implement a sending "Application", although not a proper ns3::Application
// subclass.
void StartFlow (Ptr<Socket>, Ipv4Address, uint16_t);
void WriteUntilBufferFull (Ptr<Socket>, uint32_t);
static void
CwndTracer (uint32_t oldval, uint32_t newval)
{
NS_LOG_INFO ("Moving cwnd from " << oldval << " to " << newval << " at time " << Simulator::Now ().GetSeconds () << " seconds");
}
int main (int argc, char *argv[])
{
std::string tcpModel ("ns3::TcpNewReno");
uint32_t losses = 1;
bool verbose = false;
bool tracing = true;
// Configuration and command line parameter parsing
CommandLine cmd;
cmd.AddValue ("tcpModel", "Tcp congestion control model", tcpModel);
cmd.AddValue ("losses", "number of packet losses", losses);
cmd.AddValue ("verbose", "turn on selected log components", verbose);
cmd.AddValue ("tracing", "turn on ascii and pcap tracing", tracing);
cmd.Parse (argc, argv);
Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue (tcpModel));
Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1000)); // 1000-byte packet for easier reading
Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (1));
LogComponentEnableAll (LOG_PREFIX_FUNC);
LogComponentEnable ("TcpLossResponse", LOG_LEVEL_ALL);
if (verbose)
{
//LogComponentEnableAll (LOG_PREFIX_TIME);
LogComponentEnable ("ErrorModel", LOG_LEVEL_DEBUG);
LogComponentEnable ("TcpLossResponse", LOG_LEVEL_ALL);
LogComponentEnable ("TcpNewReno", LOG_LEVEL_INFO);
LogComponentEnable ("TcpReno", LOG_LEVEL_INFO);
LogComponentEnable ("TcpTahoe", LOG_LEVEL_INFO);
LogComponentEnable ("TcpSocketBase", LOG_LEVEL_INFO);
}
// initialize the tx buffer (fill with lowercase a to z)
for (uint32_t i = 0; i < writeSize; ++i)
{
char m = toascii (97 + i % 26);
data[i] = m;
}
////////////////////////////////////////////////////////
// Topology construction
//
// Create three nodes: s1, r1, and k1
NodeContainer s1r1;
s1r1.Create (2);
Names::Add ("s1", s1r1.Get (0));
Names::Add ("r1", s1r1.Get (1));
NodeContainer r1k1;
r1k1.Add (s1r1.Get (1));
r1k1.Create (1);
Names::Add ("k1", r1k1.Get (1));
// Set up TCP/IP stack to all nodes (and create loopback device at device 0)
InternetStackHelper internet;
internet.InstallAll ();
// Connect the nodes
PointToPointHelper p2p;
p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (8000000)));
p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (0.1)));
NetDeviceContainer dev0 = p2p.Install (s1r1);
p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (800000)));
p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (100)));
NetDeviceContainer dev1 = p2p.Install (r1k1);
// Add IP addresses to each network interfaces
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
ipv4.Assign (dev0);
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer ipInterfs = ipv4.Assign (dev1);
// Set up routes to all nodes
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
////////////////////////////////////////////////////////
// Send 20000 (totalTxBytes) bytes from node s1 to node k1
//
// Create a packet sink to receive packets on node k1
uint16_t servPort = 50000; // Destination port number
PacketSinkHelper sink ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny (), servPort));
ApplicationContainer apps = sink.Install (r1k1.Get (1));
apps.Start (Seconds (0.0));
apps.Stop (Seconds (100.0));
// Create a data source to send packets on node s0.
// Instead of full application, here use the socket directly by
// registering callbacks in function StarFlow().
Ptr<Socket> localSocket = Socket::CreateSocket (s1r1.Get (0), TcpSocketFactory::GetTypeId ());
localSocket->Bind ();
Simulator::ScheduleNow (&StartFlow, localSocket, ipInterfs.GetAddress (1), servPort);
// Trace changes to the congestion window (available in Tahoe and descendents)
Config::ConnectWithoutContext ("/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow", MakeCallback (&CwndTracer));
////////////////////////////////////////////////////////
// Set up loss model at node k1
//
std::list<uint32_t> sampleList;
switch (losses)
{
case 0:
break;
case 1:
// Force a loss for 15th data packet. TCP cwnd will be at 14 segments
// (14000 bytes) when duplicate acknowledgments start to come.
sampleList.push_back (16);
break;
case 2:
sampleList.push_back (16);
sampleList.push_back (17);
break;
case 3:
sampleList.push_back (16);
sampleList.push_back (17);
sampleList.push_back (18);
break;
case 4:
sampleList.push_back (16);
sampleList.push_back (17);
sampleList.push_back (18);
sampleList.push_back (19);
break;
default:
NS_FATAL_ERROR ("Program fatal error: loss value " << losses << " not supported.");
break;
}
Ptr<ReceiveListErrorModel> pem = CreateObject<ReceiveListErrorModel> ();
pem->SetList (sampleList);
dev1.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (pem));
// One can toggle the comment for the following line on or off to see the
// effects of finite send buffer modelling. One can also change the size of
// that buffer.
// localSocket->SetAttribute("SndBufSize", UintegerValue(4096));
/////////////////////////////////////////////////////////
// Set up trace and run the simulation
//
if (tracing)
{
// Ask for ASCII and pcap traces of network traffic
AsciiTraceHelper ascii;
//Ptr<OutputStreamWrapper> osw = ascii.CreateFileStream ("tcp-loss-response.tr");
Ptr<OutputStreamWrapper> osw = Create<OutputStreamWrapper> (&std::clog);
*(osw->GetStream ()) << std::setprecision(9) << std::fixed;
p2p.EnableAsciiAll (osw);
// p2p.EnablePcap ("tcp-loss-response", 0, 0);
// p2p.EnablePcap ("tcp-loss-response", 2, 0);
}
// Finally, set up the simulator to run. The 1000 second hard limit is a
// failsafe in case some change above causes the simulation to never end
Simulator::Stop (Seconds (1000));
Simulator::Run ();
Simulator::Destroy ();
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// begin implementation of sending "Application"
void StartFlow (Ptr<Socket> localSocket,
Ipv4Address servAddress,
uint16_t servPort)
{
NS_LOG_LOGIC ("Starting flow at time " << Simulator::Now ().GetSeconds ());
localSocket->Connect (InetSocketAddress (servAddress, servPort)); // connect
// tell the tcp implementation to call WriteUntilBufferFull again
// if we blocked and new tx buffer space becomes available
localSocket->SetSendCallback (MakeCallback (&WriteUntilBufferFull));
WriteUntilBufferFull (localSocket, localSocket->GetTxAvailable ());
}
void WriteUntilBufferFull (Ptr<Socket> localSocket, uint32_t txSpace)
{
while (currentTxBytes < totalTxBytes)
{
uint32_t left = totalTxBytes - currentTxBytes;
uint32_t dataOffset = currentTxBytes % writeSize;
uint32_t toWrite = writeSize - dataOffset;
uint32_t txAvail = localSocket->GetTxAvailable ();
toWrite = std::min (toWrite, left);
toWrite = std::min (toWrite, txAvail);
if (txAvail == 0)
{
NS_LOG_LOGIC ("TCP socket buffer full at " << Simulator::Now ().GetSeconds ());
return;
};
NS_LOG_LOGIC ("Submitting " << toWrite << " bytes to TCP socket");
int amountSent = localSocket->Send (&data[dataOffset], toWrite, 0);
NS_ASSERT (amountSent > 0); // Given GetTxAvailable() non-zero, amountSent should not be zero
currentTxBytes += amountSent;
}
if (needToClose)
{
NS_LOG_LOGIC ("Close socket at " << Simulator::Now ().GetSeconds ());
localSocket->Close ();
needToClose = false;
}
}

View File

@@ -0,0 +1,283 @@
/* -*- 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, 0.1ms 10Mb/s, 0.1ms
// n0-----------------n1-----------------n2
//
// Testcases for the correctness of TCP operations.
//
// Usage (e.g.): ./waf --run="tcp-testcases --case=1"
//
#include <ctype.h>
#include <iostream>
#include <iomanip>
#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/simulator-module.h"
#include "ns3/ipv4-global-routing-helper.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("TcpTestCases");
// The number of bytes to send in this simulation.
static uint32_t totalTxBytes = 200000;
static uint32_t currentTxBytes = 0;
// Perform series of 26*40=1040 byte writes (this is a multiple of 26 since
// we want to detect data splicing in the output stream)
static const uint32_t writeSize = 1040;
uint8_t data[writeSize];
// Need to close the socket on node 0 upon finishing sending data
static bool needToClose = true;
////////////////////////////////////////////////////////////////////
// Implementing an "application" to send bytes over a TCP connection
void WriteUntilBufferFull (Ptr<Socket> localSocket, uint32_t txSpace)
{
while (currentTxBytes < totalTxBytes)
{
uint32_t left = totalTxBytes - currentTxBytes;
uint32_t dataOffset = currentTxBytes % writeSize;
uint32_t toWrite = writeSize - dataOffset;
uint32_t txAvail = localSocket->GetTxAvailable ();
toWrite = std::min (toWrite, left);
toWrite = std::min (toWrite, txAvail);
if (txAvail == 0)
{
return;
};
NS_LOG_LOGIC ("Submitting " << toWrite << " bytes to TCP socket");
int amountSent = localSocket->Send (&data[dataOffset], toWrite, 0);
NS_ASSERT (amountSent > 0); // Given GetTxAvailable() non-zero, amountSent should not be zero
currentTxBytes += amountSent;
}
if (needToClose)
{
NS_LOG_LOGIC ("Close socket at " << Simulator::Now ().GetSeconds ());
localSocket->Close ();
needToClose = false;
}
}
void StartFlow (Ptr<Socket> localSocket,
Ipv4Address servAddress,
uint16_t servPort)
{
NS_LOG_LOGIC ("Starting flow at time " << Simulator::Now ().GetSeconds ());
localSocket->Connect (InetSocketAddress (servAddress, servPort)); // connect
// tell the tcp implementation to call WriteUntilBufferFull again
// if we blocked and new tx buffer space becomes available
localSocket->SetSendCallback (MakeCallback (&WriteUntilBufferFull));
WriteUntilBufferFull (localSocket, localSocket->GetTxAvailable ());
}
// cwnd tracer
static void
CwndTracer (uint32_t oldval, uint32_t newval)
{
NS_LOG_INFO ("Moving cwnd from " << oldval << " to " << newval << " at time " << Simulator::Now ().GetSeconds () << " seconds");
}
int main (int argc, char *argv[])
{
std::string tcpModel ("ns3::TcpNewReno");
uint32_t testcase = 1;
uint32_t verbose = 0;
bool tracing = true;
// Configuration and command line parameter parsing
CommandLine cmd;
cmd.AddValue ("tcpModel", "TCP congestion control model", tcpModel);
cmd.AddValue ("testcase", "test case", testcase);
cmd.AddValue ("verbose", "turn on selected log components", verbose);
cmd.Parse (argc, argv);
Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue (tcpModel));
Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1000)); // 1000-byte packet for easier reading
Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (1));
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (20));
LogComponentEnableAll (LOG_PREFIX_FUNC);
LogComponentEnable ("TcpTestCases", LOG_LEVEL_ALL);
if (verbose)
{
//LogComponentEnableAll (LOG_PREFIX_TIME);
LogComponentEnable ("ErrorModel", LOG_LEVEL_DEBUG);
LogComponentEnable ("TcpTestCases", LOG_LEVEL_ALL);
LogComponentEnable ("TcpNewReno", LOG_LEVEL_INFO);
LogComponentEnable ("TcpReno", LOG_LEVEL_INFO);
LogComponentEnable ("TcpTahoe", LOG_LEVEL_INFO);
LogComponentEnable ("TcpSocketBase", (verbose>1)?LOG_LEVEL_ALL:LOG_LEVEL_INFO);
//LogComponentEnable ("TcpTxBuffer", LOG_LEVEL_ALL);
//LogComponentEnable ("TcpRxBuffer", LOG_LEVEL_ALL);
}
// initialize the tx buffer (fill with lowercase a to z)
for (uint32_t i = 0; i < writeSize; ++i)
{
char m = toascii (97 + i % 26);
data[i] = m;
}
////////////////////////////////////////////////////////
// Topology construction
//
// Create three nodes
NodeContainer n0n1;
n0n1.Create (2);
Names::Add ("n0", n0n1.Get (0));
Names::Add ("n1", n0n1.Get (1));
NodeContainer n1n2;
n1n2.Add (n0n1.Get (1));
n1n2.Create (1);
Names::Add ("n2", n1n2.Get (1));
// Set up TCP/IP stack to all nodes (and create loopback device at device 0)
InternetStackHelper internet;
internet.InstallAll ();
// Connect the nodes
PointToPointHelper p2p;
p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (1e6)));
p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (0.1)));
NetDeviceContainer dev0 = p2p.Install (n0n1);
NetDeviceContainer dev1 = p2p.Install (n1n2);
// Add IP addresses to each network interfaces
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
ipv4.Assign (dev0);
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer ipInterfs = ipv4.Assign (dev1);
// Set up routes to all nodes
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
////////////////////////////////////////////////////////
// A flow from node n0 to node n2
//
// Create a packet sink to receive packets on node n2
uint16_t servPort = 50000; // Destination port number
PacketSinkHelper sink ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort));
ApplicationContainer apps = sink.Install (n1n2.Get (1));
apps.Start (Seconds (0.0));
apps.Stop (Seconds (100.0));
// Create a data source to send packets on node n0
// Instead of full application, here use the socket directly by
// registering callbacks in function StarFlow().
Ptr<Socket> localSocket = Socket::CreateSocket (n0n1.Get (0), TcpSocketFactory::GetTypeId ());
localSocket->Bind ();
Simulator::ScheduleNow (&StartFlow, localSocket, ipInterfs.GetAddress (1), servPort);
// Trace changes to the congestion window (available in Tahoe and descendents)
Config::ConnectWithoutContext ("/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow", MakeCallback (&CwndTracer));
////////////////////////////////////////////////////////
// Set up different test cases: Lost model at node n1, different file size
//
std::list<uint32_t> dropListN0;
std::list<uint32_t> dropListN1;
switch (testcase)
{
case 0: // Verify connection establishment
totalTxBytes = 1000;
break;
case 1: // Verify a bigger (100 pkts) transfer: Sliding window operation, etc.
totalTxBytes = 1e5;
break;
case 2: // Survive a SYN lost
totalTxBytes = 1000;
dropListN0.push_back (0);
break;
case 3: // Survive a SYN+ACK lost
totalTxBytes = 2000;
dropListN1.push_back (0);
break;
case 4: // Survive a ACK (last packet in 3-way handshake) lost
totalTxBytes = 2000;
dropListN0.push_back (1);
break;
case 5: // Immediate FIN upon SYN_RCVD
totalTxBytes = 0;
needToClose = false;
dropListN0.push_back (1); // Hide the ACK in 3WHS
Simulator::Schedule (Seconds(0.002), &Socket::Close, localSocket);
break;
case 6: // Simulated simultaneous close
totalTxBytes = 5000;
dropListN1.push_back (5); // Hide the ACK-to-FIN from n2
break;
case 7: // FIN check 1: Lost of initiator's FIN. Shall wait until application close.
needToClose = false;
totalTxBytes = 5000;
dropListN0.push_back (7); // Hide the FIN from n0
Simulator::Schedule (Seconds(0.04), &Socket::Close, localSocket);
break;
case 8: // FIN check 2: Lost of responder's FIN. The FIN will resent after last ack timeout
totalTxBytes = 5000;
dropListN1.push_back (6); // Hide the FIN from n2
break;
default:
NS_FATAL_ERROR ("Program fatal error: specified test case not supported: " << testcase);
break;
}
Ptr<ReceiveListErrorModel> errN0 = CreateObject<ReceiveListErrorModel> ();
errN0->SetList (dropListN0);
dev0.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (errN0));
Ptr<ReceiveListErrorModel> errN1 = CreateObject<ReceiveListErrorModel> ();
errN1->SetList (dropListN1);
dev1.Get (0)->SetAttribute ("ReceiveErrorModel", PointerValue (errN1));
/////////////////////////////////////////////////////////
// Set up trace and run the simulation
//
if (tracing)
{
// Ask for ASCII and pcap traces of network traffic
AsciiTraceHelper ascii;
//Ptr<OutputStreamWrapper> osw = ascii.CreateFileStream ("tcp-loss-response.tr");
Ptr<OutputStreamWrapper> osw = Create<OutputStreamWrapper> (&std::clog);
*(osw->GetStream ()) << std::setprecision(9) << std::fixed;
p2p.EnableAsciiAll (osw);
}
// Finally, set up the simulator to run. The 1000 second hard limit is a
// failsafe in case some change above causes the simulation to never end
Simulator::Stop (Seconds (1000));
Simulator::Run ();
Simulator::Destroy ();
}

View File

@@ -21,6 +21,14 @@ def build(bld):
['point-to-point', 'internet-stack'])
obj.source = 'star.cc'
obj = bld.create_ns3_program('tcp-loss-response',
['point-to-point', 'internet-stack'])
obj.source = 'tcp-loss-response.cc'
obj = bld.create_ns3_program('tcp-testcases',
['point-to-point', 'internet-stack'])
obj.source = 'tcp-testcases.cc'
obj = bld.create_ns3_program('tcp-bulk-send',
['point-to-point', 'internet-stack'])
obj.source = 'tcp-bulk-send.cc'

View File

@@ -27,18 +27,27 @@ NS_LOG_COMPONENT_DEFINE ("OutputStreamWrapper");
namespace ns3 {
OutputStreamWrapper::OutputStreamWrapper (std::string filename, std::ios::openmode filemode)
: m_ostream (new std::ofstream ())
: m_destroyable (true)
{
std::ofstream* os = new std::ofstream ();
os->open (filename.c_str (), filemode);
m_ostream = os;
FatalImpl::RegisterStream (m_ostream);
NS_ABORT_MSG_UNLESS (os->is_open (), "AsciiTraceHelper::CreateFileStream(): " <<
"Unable to Open " << filename << " for mode " << filemode);
}
OutputStreamWrapper::OutputStreamWrapper (std::ostream* os)
: m_ostream (os), m_destroyable (false)
{
FatalImpl::RegisterStream (m_ostream);
m_ostream->open (filename.c_str (), filemode);
NS_ABORT_MSG_UNLESS (m_ostream->is_open (), "AsciiTraceHelper::CreateFileStream(): " <<
"Unable to Open " << filename << " for mode " << filemode);
NS_ABORT_MSG_UNLESS (m_ostream->good (), "Output stream is not vaild for writing.");
}
OutputStreamWrapper::~OutputStreamWrapper ()
{
FatalImpl::UnregisterStream (m_ostream);
delete m_ostream;
if (m_destroyable) delete m_ostream;
m_ostream = 0;
}

View File

@@ -71,6 +71,7 @@ class OutputStreamWrapper : public SimpleRefCount<OutputStreamWrapper>
{
public:
OutputStreamWrapper (std::string filename, std::ios::openmode filemode);
OutputStreamWrapper (std::ostream* os);
~OutputStreamWrapper ();
/**
@@ -83,7 +84,8 @@ public:
std::ostream *GetStream (void);
private:
std::ofstream *m_ostream;
std::ostream *m_ostream;
bool m_destroyable;
};
} //namespace ns3

View File

@@ -171,6 +171,9 @@ PointToPointHelper::EnableAsciiInternal (
asciiTraceHelper.HookDefaultDropSinkWithoutContext<Queue> (queue, "Drop", theStream);
asciiTraceHelper.HookDefaultDequeueSinkWithoutContext<Queue> (queue, "Dequeue", theStream);
// PhyRxDrop trace source for "d" event
asciiTraceHelper.HookDefaultDropSinkWithoutContext<PointToPointNetDevice> (device, "PhyRxDrop", theStream);
return;
}
@@ -204,6 +207,10 @@ PointToPointHelper::EnableAsciiInternal (
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/TxQueue/Drop";
Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/PhyRxDrop";
Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream));
}
NetDeviceContainer

View File

@@ -37,8 +37,6 @@
#include "nsc-tcp-socket-factory-impl.h"
#include "sim_interface.h"
#include "tcp-typedefs.h"
#include <vector>
#include <sstream>
#include <dlfcn.h>

View File

@@ -28,7 +28,6 @@
#include "nsc-tcp-l4-protocol.h"
#include "nsc-tcp-socket-impl.h"
#include "ns3/simulation-singleton.h"
#include "tcp-typedefs.h"
#include "ns3/simulator.h"
#include "ns3/packet.h"
#include "ns3/uinteger.h"
@@ -39,8 +38,8 @@
// for ntohs().
#include <arpa/inet.h>
#include <netinet/in.h>
#include "sim_interface.h"
#include "sim_errno.h"
NS_LOG_COMPONENT_DEFINE ("NscTcpSocketImpl");
@@ -63,7 +62,7 @@ NscTcpSocketImpl::GetTypeId ()
return tid;
}
NscTcpSocketImpl::NscTcpSocketImpl ()
NscTcpSocketImpl::NscTcpSocketImpl ()
: m_endPoint (0),
m_node (0),
m_tcp (0),
@@ -795,6 +794,18 @@ NscTcpSocketImpl::GetDelAckMaxCount (void) const
return m_delAckMaxCount;
}
void
NscTcpSocketImpl::SetPersistTimeout (Time timeout)
{
m_persistTimeout = timeout;
}
Time
NscTcpSocketImpl::GetPersistTimeout (void) const
{
return m_persistTimeout;
}
enum Socket::SocketErrno
NscTcpSocketImpl::GetNativeNs3Errno(int error) const
{

View File

@@ -27,7 +27,6 @@
#include "ns3/ipv4-address.h"
#include "ns3/inet-socket-address.h"
#include "ns3/event-id.h"
#include "tcp-typedefs.h"
#include "pending-data.h"
#include "ns3/sequence-number.h"
@@ -126,6 +125,8 @@ private:
virtual Time GetDelAckTimeout (void) const;
virtual void SetDelAckMaxCount (uint32_t count);
virtual uint32_t GetDelAckMaxCount (void) const;
virtual void SetPersistTimeout (Time timeout);
virtual Time GetPersistTimeout (void) const;
enum Socket::SocketErrno GetNativeNs3Errno(int err) const;
uint32_t m_delAckMaxCount;
@@ -146,7 +147,7 @@ private:
bool m_connected;
//manage the state information
States_t m_state;
TracedValue<TcpStates_t> m_state;
bool m_closeOnEmpty;
//needed to queue data when in SYN_SENT state
@@ -167,6 +168,7 @@ private:
// Timer-related members
Time m_cnTimeout;
uint32_t m_cnCount;
Time m_persistTimeout;
// Temporary queue for delivering data to application
std::queue<Ptr<Packet> > m_deliveryQueue;

View File

@@ -20,7 +20,6 @@
#include <stdint.h>
#include <iostream>
#include "tcp-socket-impl.h"
#include "tcp-header.h"
#include "ns3/buffer.h"
#include "ns3/address-utils.h"

View File

@@ -35,9 +35,8 @@
#include "ipv4-end-point.h"
#include "ipv4-l3-protocol.h"
#include "tcp-socket-factory-impl.h"
#include "tcp-socket-impl.h"
#include "tcp-newreno.h"
#include "rtt-estimator.h"
#include "tcp-typedefs.h"
#include <vector>
#include <sstream>
@@ -49,269 +48,6 @@ namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (TcpL4Protocol);
//State Machine things --------------------------------------------------------
TcpStateMachine::TcpStateMachine()
: aT (LAST_STATE, StateActionVec_t(LAST_EVENT)),
eV (MAX_FLAGS)
{
NS_LOG_FUNCTION_NOARGS ();
// Create the state table
// Closed state
aT[CLOSED][APP_LISTEN] = SA (LISTEN, NO_ACT);
aT[CLOSED][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
aT[CLOSED][APP_SEND] = SA (CLOSED, RST_TX);
aT[CLOSED][SEQ_RECV] = SA (CLOSED, NO_ACT);
aT[CLOSED][APP_CLOSE] = SA (CLOSED, NO_ACT);
aT[CLOSED][TIMEOUT] = SA (CLOSED, RST_TX);
aT[CLOSED][ACK_RX] = SA (CLOSED, RST_TX);
aT[CLOSED][SYN_RX] = SA (CLOSED, RST_TX);
aT[CLOSED][SYN_ACK_RX] = SA (CLOSED, RST_TX);
aT[CLOSED][FIN_RX] = SA (CLOSED, RST_TX);
aT[CLOSED][FIN_ACK_RX] = SA (CLOSED, RST_TX);
aT[CLOSED][RST_RX] = SA (CLOSED, CANCEL_TM);
aT[CLOSED][BAD_FLAGS] = SA (CLOSED, RST_TX);
// Listen State
// For the listen state, anything other than CONNECT or SEND
// is simply ignored....this likely indicates the child TCP
// has finished and issued unbind call, but the remote end
// has not yet closed.
aT[LISTEN][APP_LISTEN] = SA (LISTEN, NO_ACT);
aT[LISTEN][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
aT[LISTEN][APP_SEND] = SA (SYN_SENT, SYN_TX);
aT[LISTEN][SEQ_RECV] = SA (LISTEN, NO_ACT);
aT[LISTEN][APP_CLOSE] = SA (CLOSED, NO_ACT);
aT[LISTEN][TIMEOUT] = SA (LISTEN, NO_ACT);
aT[LISTEN][ACK_RX] = SA (LISTEN, NO_ACT);
aT[LISTEN][SYN_RX] = SA (LISTEN, SYN_ACK_TX);//stay in listen and fork
aT[LISTEN][SYN_ACK_RX] = SA (LISTEN, NO_ACT);
aT[LISTEN][FIN_RX] = SA (LISTEN, NO_ACT);
aT[LISTEN][FIN_ACK_RX] = SA (LISTEN, NO_ACT);
aT[LISTEN][RST_RX] = SA (LISTEN, NO_ACT);
aT[LISTEN][BAD_FLAGS] = SA (LISTEN, NO_ACT);
// Syn Sent State
aT[SYN_SENT][APP_LISTEN] = SA (CLOSED, RST_TX);
aT[SYN_SENT][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
aT[SYN_SENT][APP_SEND] = SA (SYN_SENT, NO_ACT);
aT[SYN_SENT][SEQ_RECV] = SA (ESTABLISHED, NEW_SEQ_RX);
aT[SYN_SENT][APP_CLOSE] = SA (CLOSED, RST_TX);
aT[SYN_SENT][TIMEOUT] = SA (CLOSED, NO_ACT);
aT[SYN_SENT][ACK_RX] = SA (SYN_SENT, NO_ACT);
aT[SYN_SENT][SYN_RX] = SA (SYN_RCVD, SYN_ACK_TX);
aT[SYN_SENT][SYN_ACK_RX] = SA (ESTABLISHED, ACK_TX_1);
aT[SYN_SENT][FIN_RX] = SA (CLOSED, RST_TX);
aT[SYN_SENT][FIN_ACK_RX] = SA (CLOSED, RST_TX);
aT[SYN_SENT][RST_RX] = SA (CLOSED, APP_NOTIFY);
aT[SYN_SENT][BAD_FLAGS] = SA (CLOSED, RST_TX);
// Syn Recvd State
aT[SYN_RCVD][APP_LISTEN] = SA (CLOSED, RST_TX);
aT[SYN_RCVD][APP_CONNECT] = SA (CLOSED, RST_TX);
aT[SYN_RCVD][APP_SEND] = SA (CLOSED, RST_TX);
aT[SYN_RCVD][SEQ_RECV] = SA (ESTABLISHED, NEW_SEQ_RX);
aT[SYN_RCVD][APP_CLOSE] = SA (FIN_WAIT_1, FIN_TX);
aT[SYN_RCVD][TIMEOUT] = SA (CLOSED, RST_TX);
aT[SYN_RCVD][ACK_RX] = SA (ESTABLISHED, SERV_NOTIFY);
aT[SYN_RCVD][SYN_RX] = SA (SYN_RCVD, SYN_ACK_TX);
aT[SYN_RCVD][SYN_ACK_RX] = SA (CLOSED, RST_TX);
aT[SYN_RCVD][FIN_RX] = SA (CLOSED, RST_TX);
aT[SYN_RCVD][FIN_ACK_RX] = SA (CLOSE_WAIT, PEER_CLOSE);
aT[SYN_RCVD][RST_RX] = SA (CLOSED, CANCEL_TM);
aT[SYN_RCVD][BAD_FLAGS] = SA (CLOSED, RST_TX);
// Established State
aT[ESTABLISHED][APP_LISTEN] = SA (CLOSED, RST_TX);
aT[ESTABLISHED][APP_CONNECT]= SA (CLOSED, RST_TX);
aT[ESTABLISHED][APP_SEND] = SA (ESTABLISHED,TX_DATA);
aT[ESTABLISHED][SEQ_RECV] = SA (ESTABLISHED,NEW_SEQ_RX);
aT[ESTABLISHED][APP_CLOSE] = SA (FIN_WAIT_1, FIN_TX);
aT[ESTABLISHED][TIMEOUT] = SA (ESTABLISHED,RETX);
aT[ESTABLISHED][ACK_RX] = SA (ESTABLISHED,NEW_ACK);
aT[ESTABLISHED][SYN_RX] = SA (SYN_RCVD, SYN_ACK_TX);
aT[ESTABLISHED][SYN_ACK_RX] = SA (ESTABLISHED,NO_ACT);
aT[ESTABLISHED][FIN_RX] = SA (CLOSE_WAIT, PEER_CLOSE);
aT[ESTABLISHED][FIN_ACK_RX] = SA (CLOSE_WAIT, PEER_CLOSE);
aT[ESTABLISHED][RST_RX] = SA (CLOSED, CANCEL_TM);
aT[ESTABLISHED][BAD_FLAGS] = SA (CLOSED, RST_TX);
// Close Wait State
aT[CLOSE_WAIT][APP_LISTEN] = SA (CLOSED, RST_TX);
aT[CLOSE_WAIT][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
aT[CLOSE_WAIT][APP_SEND] = SA (CLOSE_WAIT, TX_DATA);
aT[CLOSE_WAIT][SEQ_RECV] = SA (CLOSE_WAIT, NEW_SEQ_RX);
aT[CLOSE_WAIT][APP_CLOSE] = SA (LAST_ACK, FIN_ACK_TX);
aT[CLOSE_WAIT][TIMEOUT] = SA (CLOSE_WAIT, NO_ACT);
aT[CLOSE_WAIT][ACK_RX] = SA (CLOSE_WAIT, NEW_ACK);
aT[CLOSE_WAIT][SYN_RX] = SA (CLOSED, RST_TX);
aT[CLOSE_WAIT][SYN_ACK_RX] = SA (CLOSED, RST_TX);
aT[CLOSE_WAIT][FIN_RX] = SA (CLOSE_WAIT, ACK_TX);
aT[CLOSE_WAIT][FIN_ACK_RX] = SA (CLOSE_WAIT, ACK_TX);
aT[CLOSE_WAIT][RST_RX] = SA (CLOSED, CANCEL_TM);
aT[CLOSE_WAIT][BAD_FLAGS] = SA (CLOSED, RST_TX);
// Close Last Ack State
aT[LAST_ACK][APP_LISTEN] = SA (CLOSED, RST_TX);
aT[LAST_ACK][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
aT[LAST_ACK][APP_SEND] = SA (CLOSED, RST_TX);
aT[LAST_ACK][SEQ_RECV] = SA (LAST_ACK, NEW_SEQ_RX);
aT[LAST_ACK][APP_CLOSE] = SA (CLOSED, NO_ACT);
aT[LAST_ACK][TIMEOUT] = SA (CLOSED, NO_ACT);
aT[LAST_ACK][ACK_RX] = SA (LAST_ACK, NO_ACT);
aT[LAST_ACK][FIN_ACKED] = SA (CLOSED, APP_CLOSED);
aT[LAST_ACK][SYN_RX] = SA (CLOSED, RST_TX);
aT[LAST_ACK][SYN_ACK_RX] = SA (CLOSED, RST_TX);
aT[LAST_ACK][FIN_RX] = SA (LAST_ACK, FIN_ACK_TX);
aT[LAST_ACK][FIN_ACK_RX] = SA (CLOSED, NO_ACT);
aT[LAST_ACK][RST_RX] = SA (CLOSED, CANCEL_TM);
aT[LAST_ACK][BAD_FLAGS] = SA (CLOSED, RST_TX);
// FIN_WAIT_1 state
aT[FIN_WAIT_1][APP_LISTEN] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_1][APP_CONNECT] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_1][APP_SEND] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_1][SEQ_RECV] = SA (FIN_WAIT_1, NEW_SEQ_RX);
aT[FIN_WAIT_1][APP_CLOSE] = SA (FIN_WAIT_1, NO_ACT);
aT[FIN_WAIT_1][TIMEOUT] = SA (FIN_WAIT_1, NO_ACT);
aT[FIN_WAIT_1][ACK_RX] = SA (FIN_WAIT_1, NEW_ACK);
aT[FIN_WAIT_1][FIN_ACKED] = SA (FIN_WAIT_2, NEW_ACK);
aT[FIN_WAIT_1][SYN_RX] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_1][SYN_ACK_RX] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_1][FIN_RX] = SA (CLOSING, ACK_TX);
aT[FIN_WAIT_1][FIN_ACK_RX] = SA (TIMED_WAIT, ACK_TX);
aT[FIN_WAIT_1][RST_RX] = SA (CLOSED, CANCEL_TM);
aT[FIN_WAIT_1][BAD_FLAGS] = SA (CLOSED, RST_TX);
// FIN_WAIT_2 state
aT[FIN_WAIT_2][APP_LISTEN] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_2][APP_CONNECT] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_2][APP_SEND] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_2][SEQ_RECV] = SA (FIN_WAIT_2, NEW_SEQ_RX);
aT[FIN_WAIT_2][APP_CLOSE] = SA (FIN_WAIT_2, NO_ACT);
aT[FIN_WAIT_2][TIMEOUT] = SA (FIN_WAIT_2, NO_ACT);
aT[FIN_WAIT_2][ACK_RX] = SA (FIN_WAIT_2, NEW_ACK);
aT[FIN_WAIT_2][SYN_RX] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_2][SYN_ACK_RX] = SA (CLOSED, RST_TX);
aT[FIN_WAIT_2][FIN_RX] = SA (TIMED_WAIT, ACK_TX);
aT[FIN_WAIT_2][FIN_ACK_RX] = SA (TIMED_WAIT, ACK_TX);
aT[FIN_WAIT_2][RST_RX] = SA (CLOSED, CANCEL_TM);
aT[FIN_WAIT_2][BAD_FLAGS] = SA (CLOSED, RST_TX);
// CLOSING state
aT[CLOSING][APP_LISTEN] = SA (CLOSED, RST_TX);
aT[CLOSING][APP_CONNECT] = SA (CLOSED, RST_TX);
aT[CLOSING][APP_SEND] = SA (CLOSED, RST_TX);
aT[CLOSING][SEQ_RECV] = SA (CLOSED, RST_TX);
aT[CLOSING][APP_CLOSE] = SA (CLOSED, RST_TX);
aT[CLOSING][TIMEOUT] = SA (CLOSING, NO_ACT);
aT[CLOSING][ACK_RX] = SA (CLOSING, NO_ACT);
aT[CLOSING][FIN_ACKED] = SA (TIMED_WAIT, NO_ACT);
aT[CLOSING][SYN_RX] = SA (CLOSED, RST_TX);
aT[CLOSING][SYN_ACK_RX] = SA (CLOSED, RST_TX);
aT[CLOSING][FIN_RX] = SA (CLOSED, ACK_TX);
aT[CLOSING][FIN_ACK_RX] = SA (CLOSED, ACK_TX);
aT[CLOSING][RST_RX] = SA (CLOSED, CANCEL_TM);
aT[CLOSING][BAD_FLAGS] = SA (CLOSED, RST_TX);
// TIMED_WAIT state
aT[TIMED_WAIT][APP_LISTEN] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][APP_CONNECT] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][APP_SEND] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][SEQ_RECV] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][APP_CLOSE] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][TIMEOUT] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][ACK_RX] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][SYN_RX] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][SYN_ACK_RX] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][FIN_RX] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][FIN_ACK_RX] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][RST_RX] = SA (TIMED_WAIT, NO_ACT);
aT[TIMED_WAIT][BAD_FLAGS] = SA (TIMED_WAIT, NO_ACT);
// Create the flags lookup table
eV[ 0x00] = SEQ_RECV; // No flags
eV[ 0x01] = FIN_RX; // Fin
eV[ 0x02] = SYN_RX; // Syn
eV[ 0x03] = BAD_FLAGS; // Illegal
eV[ 0x04] = RST_RX; // Rst
eV[ 0x05] = BAD_FLAGS; // Illegal
eV[ 0x06] = BAD_FLAGS; // Illegal
eV[ 0x07] = BAD_FLAGS; // Illegal
eV[ 0x08] = SEQ_RECV; // Psh flag is not used
eV[ 0x09] = FIN_RX; // Fin
eV[ 0x0a] = SYN_RX; // Syn
eV[ 0x0b] = BAD_FLAGS; // Illegal
eV[ 0x0c] = RST_RX; // Rst
eV[ 0x0d] = BAD_FLAGS; // Illegal
eV[ 0x0e] = BAD_FLAGS; // Illegal
eV[ 0x0f] = BAD_FLAGS; // Illegal
eV[ 0x10] = ACK_RX; // Ack
eV[ 0x11] = FIN_ACK_RX;// Fin/Ack
eV[ 0x12] = SYN_ACK_RX;// Syn/Ack
eV[ 0x13] = BAD_FLAGS; // Illegal
eV[ 0x14] = RST_RX; // Rst
eV[ 0x15] = BAD_FLAGS; // Illegal
eV[ 0x16] = BAD_FLAGS; // Illegal
eV[ 0x17] = BAD_FLAGS; // Illegal
eV[ 0x18] = ACK_RX; // Ack
eV[ 0x19] = FIN_ACK_RX;// Fin/Ack
eV[ 0x1a] = SYN_ACK_RX;// Syn/Ack
eV[ 0x1b] = BAD_FLAGS; // Illegal
eV[ 0x1c] = RST_RX; // Rst
eV[ 0x1d] = BAD_FLAGS; // Illegal
eV[ 0x1e] = BAD_FLAGS; // Illegal
eV[ 0x1f] = BAD_FLAGS; // Illegal
eV[ 0x20] = SEQ_RECV; // No flags (Urgent not presently used)
eV[ 0x21] = FIN_RX; // Fin
eV[ 0x22] = SYN_RX; // Syn
eV[ 0x23] = BAD_FLAGS; // Illegal
eV[ 0x24] = RST_RX; // Rst
eV[ 0x25] = BAD_FLAGS; // Illegal
eV[ 0x26] = BAD_FLAGS; // Illegal
eV[ 0x27] = BAD_FLAGS; // Illegal
eV[ 0x28] = SEQ_RECV; // Psh flag is not used
eV[ 0x29] = FIN_RX; // Fin
eV[ 0x2a] = SYN_RX; // Syn
eV[ 0x2b] = BAD_FLAGS; // Illegal
eV[ 0x2c] = RST_RX; // Rst
eV[ 0x2d] = BAD_FLAGS; // Illegal
eV[ 0x2e] = BAD_FLAGS; // Illegal
eV[ 0x2f] = BAD_FLAGS; // Illegal
eV[ 0x30] = ACK_RX; // Ack (Urgent not used)
eV[ 0x31] = FIN_ACK_RX;// Fin/Ack
eV[ 0x32] = SYN_ACK_RX;// Syn/Ack
eV[ 0x33] = BAD_FLAGS; // Illegal
eV[ 0x34] = RST_RX; // Rst
eV[ 0x35] = BAD_FLAGS; // Illegal
eV[ 0x36] = BAD_FLAGS; // Illegal
eV[ 0x37] = BAD_FLAGS; // Illegal
eV[ 0x38] = ACK_RX; // Ack
eV[ 0x39] = FIN_ACK_RX;// Fin/Ack
eV[ 0x3a] = SYN_ACK_RX;// Syn/Ack
eV[ 0x3b] = BAD_FLAGS; // Illegal
eV[ 0x3c] = RST_RX; // Rst
eV[ 0x3d] = BAD_FLAGS; // Illegal
eV[ 0x3e] = BAD_FLAGS; // Illegal
eV[ 0x3f] = BAD_FLAGS; // Illegal
}
SA TcpStateMachine::Lookup (States_t s, Events_t e)
{
NS_LOG_FUNCTION (this << s << e);
return aT[s][e];
}
Events_t TcpStateMachine::FlagsEvent (uint8_t f)
{
NS_LOG_FUNCTION (this << f);
// Lookup event from flags
if (f >= MAX_FLAGS) return BAD_FLAGS;
return eV[f]; // Look up flags event
}
static TcpStateMachine tcpStateMachine; //only instance of a TcpStateMachine
//TcpL4Protocol stuff----------------------------------------------------------
#undef NS_LOG_APPEND_CONTEXT
@@ -321,29 +57,26 @@ static TcpStateMachine tcpStateMachine; //only instance of a TcpStateMachine
/* see http://www.iana.org/assignments/protocol-numbers */
const uint8_t TcpL4Protocol::PROT_NUMBER = 6;
ObjectFactory
TcpL4Protocol::GetDefaultRttEstimatorFactory (void)
{
ObjectFactory factory;
factory.SetTypeId (RttMeanDeviation::GetTypeId ());
return factory;
}
TypeId
TcpL4Protocol::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpL4Protocol")
.SetParent<Ipv4L4Protocol> ()
.AddConstructor<TcpL4Protocol> ()
.AddAttribute ("RttEstimatorFactory",
"How RttEstimator objects are created.",
ObjectFactoryValue (GetDefaultRttEstimatorFactory ()),
MakeObjectFactoryAccessor (&TcpL4Protocol::m_rttFactory),
MakeObjectFactoryChecker ())
.AddAttribute ("RttEstimatorType",
"Type of RttEstimator objects.",
TypeIdValue (RttMeanDeviation::GetTypeId()),
MakeTypeIdAccessor (&TcpL4Protocol::m_rttTypeId),
MakeTypeIdChecker ())
.AddAttribute ("SocketType",
"Socket type of TCP objects.",
TypeIdValue (TcpNewReno::GetTypeId()),
MakeTypeIdAccessor (&TcpL4Protocol::m_socketTypeId),
MakeTypeIdChecker ())
.AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
ObjectVectorValue (),
MakeObjectVectorAccessor (&TcpL4Protocol::m_sockets),
MakeObjectVectorChecker<TcpSocketImpl> ())
MakeObjectVectorChecker<TcpSocketBase> ())
;
return tid;
}
@@ -403,7 +136,7 @@ void
TcpL4Protocol::DoDispose (void)
{
NS_LOG_FUNCTION_NOARGS ();
for (std::vector<Ptr<TcpSocketImpl> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
for (std::vector<Ptr<TcpSocketBase> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
{
*i = 0;
}
@@ -420,11 +153,15 @@ TcpL4Protocol::DoDispose (void)
}
Ptr<Socket>
TcpL4Protocol::CreateSocket (void)
TcpL4Protocol::CreateSocket (TypeId socketTypeId)
{
NS_LOG_FUNCTION_NOARGS ();
Ptr<RttEstimator> rtt = m_rttFactory.Create<RttEstimator> ();
Ptr<TcpSocketImpl> socket = CreateObject<TcpSocketImpl> ();
ObjectFactory rttFactory;
ObjectFactory socketFactory;
rttFactory.SetTypeId(m_rttTypeId);
socketFactory.SetTypeId(socketTypeId);
Ptr<RttEstimator> rtt = rttFactory.Create<RttEstimator> ();
Ptr<TcpSocketBase> socket = socketFactory.Create<TcpSocketBase> ();
socket->SetNode (m_node);
socket->SetTcp (this);
socket->SetRtt (rtt);
@@ -432,6 +169,12 @@ TcpL4Protocol::CreateSocket (void)
return socket;
}
Ptr<Socket>
TcpL4Protocol::CreateSocket (void)
{
return CreateSocket (m_socketTypeId);
}
Ipv4EndPoint *
TcpL4Protocol::Allocate (void)
{

View File

@@ -37,7 +37,7 @@ class Socket;
class TcpHeader;
class Ipv4EndPointDemux;
class Ipv4Interface;
class TcpSocketImpl;
class TcpSocketBase;
class Ipv4EndPoint;
/**
@@ -69,6 +69,7 @@ public:
* of the TCP protocol
*/
Ptr<Socket> CreateSocket (void);
Ptr<Socket> CreateSocket (TypeId socketTypeId);
Ipv4EndPoint *Allocate (void);
Ipv4EndPoint *Allocate (Ipv4Address address);
@@ -115,16 +116,16 @@ protected:
private:
Ptr<Node> m_node;
Ipv4EndPointDemux *m_endPoints;
ObjectFactory m_rttFactory;
TypeId m_rttTypeId;
TypeId m_socketTypeId;
private:
friend class TcpSocketImpl;
friend class TcpSocketBase;
void SendPacket (Ptr<Packet>, const TcpHeader &,
Ipv4Address, Ipv4Address, Ptr<NetDevice> oif = 0);
static ObjectFactory GetDefaultRttEstimatorFactory (void);
TcpL4Protocol (const TcpL4Protocol &o);
TcpL4Protocol &operator = (const TcpL4Protocol &o);
std::vector<Ptr<TcpSocketImpl> > m_sockets;
std::vector<Ptr<TcpSocketBase> > m_sockets;
};
}; // namespace ns3

View File

@@ -0,0 +1,221 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#define NS_LOG_APPEND_CONTEXT \
if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
#include "tcp-newreno.h"
#include "ns3/log.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/simulator.h"
#include "ns3/abort.h"
#include "ns3/node.h"
NS_LOG_COMPONENT_DEFINE ("TcpNewReno");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (TcpNewReno);
TypeId
TcpNewReno::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpNewReno")
.SetParent<TcpSocketBase> ()
.AddConstructor<TcpNewReno> ()
.AddTraceSource ("CongestionWindow",
"The TCP connection's congestion window",
MakeTraceSourceAccessor (&TcpNewReno::m_cWnd))
;
return tid;
}
TcpNewReno::TcpNewReno (void) : m_inFastRec (false)
{
NS_LOG_FUNCTION (this);
}
TcpNewReno::TcpNewReno (const TcpNewReno& sock)
: TcpSocketBase (sock),
m_cWnd (sock.m_cWnd),
m_ssThresh (sock.m_ssThresh),
m_initialCWnd (sock.m_initialCWnd),
m_inFastRec (false)
{
NS_LOG_FUNCTION (this);
NS_LOG_LOGIC ("Invoked the copy constructor");
}
TcpNewReno::~TcpNewReno (void)
{
}
void
TcpNewReno::SetNode (Ptr<Node> node)
{
TcpSocketBase::SetNode (node);
/*
* Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must
* not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and
* m_segmentSize are set by the attribute system in ns3::TcpSocket.
*/
m_cWnd = m_initialCWnd * m_segmentSize;
}
/** Limit the size of in-flight data by cwnd and receiver's rxwin */
uint32_t
TcpNewReno::Window (void)
{
NS_LOG_FUNCTION (this);
return std::min (m_rWnd.Get (), m_cWnd.Get ());
}
Ptr<TcpSocketBase>
TcpNewReno::Fork (void)
{
return CopyObject<TcpNewReno> (this);
}
/** New ACK (up to seqnum seq) received. Increase cwnd and call TcpSocketBase::NewAck() */
void
TcpNewReno::NewAck (const SequenceNumber32& seq)
{
NS_LOG_FUNCTION (this << seq);
NS_LOG_LOGIC ("TcpNewReno receieved ACK for seq " << seq <<
" cwnd " << m_cWnd <<
" ssthresh " << m_ssThresh);
// Check for exit condition of fast recovery
if (m_inFastRec && seq < m_recover)
{ // Partial ACK, partial window deflation (RFC2582 sec.3 bullet #5 paragraph 3)
m_cWnd += m_segmentSize; // increase cwnd
NS_LOG_INFO ("Partial ACK in fast recovery: cwnd set to " << m_cWnd);
TcpSocketBase::NewAck(seq); // update m_nextTxSequence and send new data if allowed by window
DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet
return;
}
else if (m_inFastRec && seq >= m_recover)
{ // Full ACK (RFC2582 sec.3 bullet #5 paragraph 2, option 1)
m_cWnd = std::min (m_ssThresh, BytesInFlight () + m_segmentSize);
m_inFastRec = false;
NS_LOG_INFO ("Received full ACK. Leaving fast recovery with cwnd set to " << m_cWnd);
}
// Increase of cwnd based on current phase (slow start or congestion avoidance)
if (m_cWnd < m_ssThresh)
{ // Slow start mode, add one segSize to cWnd. Default m_ssThresh is 65535. (RFC2001, sec.1)
m_cWnd += m_segmentSize;
NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
}
else
{ // Congestion avoidance mode, increase by (segSize*segSize)/cwnd. (RFC2581, sec.3.1)
// To increase cwnd for one segSize per RTT, it should be (ackBytes*segSize)/cwnd
double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get ();
adder = std::max (1.0, adder);
m_cWnd += static_cast<uint32_t> (adder);
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
}
// Complete newAck processing
TcpSocketBase::NewAck (seq);
}
/** Cut cwnd and enter fast recovery mode upon triple dupack */
void
TcpNewReno::DupAck (const TcpHeader& t, uint32_t count)
{
if (count == 3 && ! m_inFastRec)
{ // triple duplicate ack triggers fast retransmit (RFC2582 sec.3 bullet #1)
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
m_cWnd = m_ssThresh + 3 * m_segmentSize;
m_recover = m_highTxMark;
m_inFastRec = true;
NS_LOG_INFO ("Triple dupack. Enter fast recovery mode. Reset cwnd to " << m_cWnd <<
", ssthresh to " << m_ssThresh << " at fast recovery seqnum " << m_recover);
DoRetransmit ();
}
else if (m_inFastRec)
{ // Increase cwnd for every additional dupack (RFC2582, sec.3 bullet #3)
m_cWnd += m_segmentSize;
NS_LOG_INFO ("Dupack in fast recovery mode. Increase cwnd to " << m_cWnd);
SendPendingData (m_connected);
};
}
/** Retransmit timeout */
void
TcpNewReno::Retransmit (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
m_inFastRec = false;
// If erroneous timeout in closed/timed-wait state, just return
if (m_state == CLOSED || m_state == TIME_WAIT) return;
// If all data are received, just return
if (m_txBuffer.HeadSequence () >= m_nextTxSequence) return;
// According to RFC2581 sec.3.1, upon RTO, ssthresh is set to half of flight
// size and cwnd is set to 1*MSS, then the lost packet is retransmitted and
// TCP back to slow start
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
m_cWnd = m_segmentSize;
m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack
NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
m_rtt->IncreaseMultiplier (); // Double the next RTO
DoRetransmit (); // Retransmit the packet
}
void
TcpNewReno::SetSegSize (uint32_t size)
{
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpNewReno::SetSegSize() cannot change segment size after connection started.");
m_segmentSize = size;
m_cWnd = m_initialCWnd * m_segmentSize;
}
void
TcpNewReno::SetSSThresh (uint32_t threshold)
{
m_ssThresh = threshold;
}
uint32_t
TcpNewReno::GetSSThresh (void) const
{
return m_ssThresh;
}
void
TcpNewReno::SetInitialCwnd (uint32_t cwnd)
{
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpNewReno::SetInitialCwnd() cannot change initial cwnd after connection started.");
m_initialCWnd = cwnd;
m_cWnd = m_initialCWnd * m_segmentSize;
}
uint32_t
TcpNewReno::GetInitialCwnd (void) const
{
return m_initialCWnd;
}
} // namespace ns3

View File

@@ -0,0 +1,74 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#ifndef TCP_NEWRENO_H
#define TCP_NEWRENO_H
#include "tcp-socket-base.h"
namespace ns3 {
/**
* \ingroup socket
* \ingroup tcp
*
* \brief An implementation of a stream socket using TCP.
*
* This class contains the NewReno implementation of TCP, as of RFC2582.
*/
class TcpNewReno : public TcpSocketBase
{
public:
static TypeId GetTypeId (void);
/**
* Create an unbound tcp socket.
*/
TcpNewReno (void);
TcpNewReno (const TcpNewReno& sock);
virtual ~TcpNewReno (void);
// Set associated Node, TcpL4Protocol, RttEstimator to this socket
virtual void SetNode (Ptr<Node> node);
protected:
virtual uint32_t Window (void); // Return the max possible number of unacked bytes
virtual Ptr<TcpSocketBase> Fork (void); // Call CopyObject<TcpNewReno> to clone me
virtual void NewAck (SequenceNumber32 const& seq); // Inc cwnd and call NewAck() of parent
virtual void DupAck (const TcpHeader& t, uint32_t count); // Halving cwnd and reset nextTxSequence
virtual void Retransmit (void); // Exit fast recovery upon retransmit timeout
// Implementing ns3::TcpSocket -- Attribute get/set
virtual void SetSegSize (uint32_t size);
virtual void SetSSThresh (uint32_t threshold);
virtual uint32_t GetSSThresh (void) const;
virtual void SetInitialCwnd (uint32_t cwnd);
virtual uint32_t GetInitialCwnd (void) const;
protected:
TracedValue<uint32_t> m_cWnd; //< Congestion window
uint32_t m_ssThresh; //< Slow Start Threshold
uint32_t m_initialCWnd; //< Initial cWnd value
SequenceNumber32 m_recover; //< Previous highest Tx seqnum for fast recovery
bool m_inFastRec; //< currently in fast recovery
};
} // namespace ns3
#endif /* TCP_NEWRENO_H */

View File

@@ -0,0 +1,212 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#define NS_LOG_APPEND_CONTEXT \
if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
#include "tcp-reno.h"
#include "ns3/log.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/simulator.h"
#include "ns3/abort.h"
#include "ns3/node.h"
NS_LOG_COMPONENT_DEFINE ("TcpReno");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (TcpReno);
TypeId
TcpReno::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpReno")
.SetParent<TcpSocketBase> ()
.AddConstructor<TcpReno> ()
.AddTraceSource ("CongestionWindow",
"The TCP connection's congestion window",
MakeTraceSourceAccessor (&TcpReno::m_cWnd))
;
return tid;
}
TcpReno::TcpReno (void) : m_inFastRec (false)
{
NS_LOG_FUNCTION (this);
}
TcpReno::TcpReno (const TcpReno& sock)
: TcpSocketBase (sock),
m_cWnd (sock.m_cWnd),
m_ssThresh (sock.m_ssThresh),
m_initialCWnd (sock.m_initialCWnd),
m_inFastRec (false)
{
NS_LOG_FUNCTION (this);
NS_LOG_LOGIC ("Invoked the copy constructor");
}
TcpReno::~TcpReno (void)
{
}
void
TcpReno::SetNode (Ptr<Node> node)
{
TcpSocketBase::SetNode (node);
/*
* Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must
* not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and
* m_segmentSize are set by the attribute system in ns3::TcpSocket.
*/
m_cWnd = m_initialCWnd * m_segmentSize;
}
/** Limit the size of in-flight data by cwnd and receiver's rxwin */
uint32_t
TcpReno::Window (void)
{
NS_LOG_FUNCTION (this);
return std::min (m_rWnd.Get (), m_cWnd.Get ());
}
Ptr<TcpSocketBase>
TcpReno::Fork (void)
{
return CopyObject<TcpReno> (this);
}
/** New ACK (up to seqnum seq) received. Increase cwnd and call TcpSocketBase::NewAck() */
void
TcpReno::NewAck (const SequenceNumber32& seq)
{
NS_LOG_FUNCTION (this << seq);
NS_LOG_LOGIC ("TcpReno receieved ACK for seq " << seq <<
" cwnd " << m_cWnd <<
" ssthresh " << m_ssThresh);
// Check for exit condition of fast recovery
if (m_inFastRec)
{ // RFC2001, sec.4; RFC2581, sec.3.2
// First new ACK after fast recovery: reset cwnd
m_cWnd = m_ssThresh;
m_inFastRec = false;
NS_LOG_INFO ("Reset cwnd to " << m_cWnd);
};
// Increase of cwnd based on current phase (slow start or congestion avoidance)
if (m_cWnd < m_ssThresh)
{ // Slow start mode, add one segSize to cWnd. Default m_ssThresh is 65535. (RFC2001, sec.1)
m_cWnd += m_segmentSize;
NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
}
else
{ // Congestion avoidance mode, increase by (segSize*segSize)/cwnd. (RFC2581, sec.3.1)
// To increase cwnd for one segSize per RTT, it should be (ackBytes*segSize)/cwnd
double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get ();
adder = std::max (1.0, adder);
m_cWnd += static_cast<uint32_t> (adder);
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
}
// Complete newAck processing
TcpSocketBase::NewAck (seq);
}
// Fast recovery and fast retransmit
void
TcpReno::DupAck (const TcpHeader& t, uint32_t count)
{
NS_LOG_FUNCTION (this << "t " << count);
if (count == 3 && ! m_inFastRec)
{ // triple duplicate ack triggers fast retransmit (RFC2581, sec.3.2)
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
m_cWnd = m_ssThresh + 3 * m_segmentSize;
m_inFastRec = true;
NS_LOG_INFO ("Triple dupack. Reset cwnd to " << m_cWnd << ", ssthresh to " << m_ssThresh);
DoRetransmit ();
}
else if (m_inFastRec)
{ // In fast recovery, inc cwnd for every additional dupack (RFC2581, sec.3.2)
m_cWnd += m_segmentSize;
NS_LOG_INFO ("Increased cwnd to " << m_cWnd);
SendPendingData (m_connected);
};
}
// Retransmit timeout
void TcpReno::Retransmit (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
m_inFastRec = false;
// If erroneous timeout in closed/timed-wait state, just return
if (m_state == CLOSED || m_state == TIME_WAIT) return;
// If all data are received, just return
if (m_txBuffer.HeadSequence () >= m_nextTxSequence) return;
// According to RFC2581 sec.3.1, upon RTO, ssthresh is set to half of flight
// size and cwnd is set to 1*MSS, then the lost packet is retransmitted and
// TCP back to slow start
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
m_cWnd = m_segmentSize;
m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack
NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
m_rtt->IncreaseMultiplier (); // Double the next RTO
DoRetransmit (); // Retransmit the packet
}
void
TcpReno::SetSegSize (uint32_t size)
{
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpReno::SetSegSize() cannot change segment size after connection started.");
m_segmentSize = size;
m_cWnd = m_initialCWnd * m_segmentSize;
}
void
TcpReno::SetSSThresh (uint32_t threshold)
{
m_ssThresh = threshold;
}
uint32_t
TcpReno::GetSSThresh (void) const
{
return m_ssThresh;
}
void
TcpReno::SetInitialCwnd (uint32_t cwnd)
{
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpReno::SetInitialCwnd() cannot change initial cwnd after connection started.");
m_initialCWnd = cwnd;
m_cWnd = m_initialCWnd * m_segmentSize;
}
uint32_t
TcpReno::GetInitialCwnd (void) const
{
return m_initialCWnd;
}
} // namespace ns3

View File

@@ -0,0 +1,75 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#ifndef TCP_RENO_H
#define TCP_RENO_H
#include "tcp-socket-base.h"
namespace ns3 {
/**
* \ingroup socket
* \ingroup tcp
*
* \brief An implementation of a stream socket using TCP.
*
* This class contains the Reno implementation of TCP, according to RFC2581,
* except sec.4.1 "re-starting idle connections", which we do not detect for
* idleness and thus no slow start upon resumption.
*/
class TcpReno : public TcpSocketBase
{
public:
static TypeId GetTypeId (void);
/**
* Create an unbound tcp socket.
*/
TcpReno (void);
TcpReno (const TcpReno& sock);
virtual ~TcpReno (void);
// Set associated Node, TcpL4Protocol, RttEstimator to this socket
virtual void SetNode (Ptr<Node> node);
protected:
virtual uint32_t Window (void); // Return the max possible number of unacked bytes
virtual Ptr<TcpSocketBase> Fork (void); // Call CopyObject<TcpReno> to clone me
virtual void NewAck (const SequenceNumber32& seq); // Inc cwnd and call NewAck() of parent
virtual void DupAck (const TcpHeader& t, uint32_t count); // Fast retransmit
virtual void Retransmit (void); // Retransmit timeout
// Implementing ns3::TcpSocket -- Attribute get/set
virtual void SetSegSize (uint32_t size);
virtual void SetSSThresh (uint32_t threshold);
virtual uint32_t GetSSThresh (void) const;
virtual void SetInitialCwnd (uint32_t cwnd);
virtual uint32_t GetInitialCwnd (void) const;
protected:
TracedValue<uint32_t> m_cWnd; //< Congestion window
uint32_t m_ssThresh; //< Slow Start Threshold
uint32_t m_initialCWnd; //< Initial cWnd value
bool m_inFastRec; //< currently in fast recovery
};
} // namespace ns3
#endif /* TCP_RENO_H */

View File

@@ -0,0 +1,91 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#include "tcp-rfc793.h"
#include "ns3/log.h"
NS_LOG_COMPONENT_DEFINE ("TcpRfc793");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (TcpRfc793);
TypeId
TcpRfc793::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpRfc793")
.SetParent<TcpSocketBase> ()
.AddConstructor<TcpRfc793> ()
;
return tid;
}
TcpRfc793::TcpRfc793 (void)
{
NS_LOG_FUNCTION (this);
SetDelAckMaxCount(0); // Delayed ACK is not in RFC793
}
TcpRfc793::TcpRfc793 (const TcpRfc793& sock) : TcpSocketBase (sock)
{
}
TcpRfc793::~TcpRfc793 (void)
{
}
Ptr<TcpSocketBase>
TcpRfc793::Fork (void)
{
return CopyObject<TcpRfc793> (this);
}
void
TcpRfc793::DupAck (const TcpHeader& t, uint32_t count)
{
}
void
TcpRfc793::SetSSThresh (uint32_t threshold)
{
NS_LOG_WARN ("DoD TCP does not perform slow start");
}
uint32_t
TcpRfc793::GetSSThresh (void) const
{
NS_LOG_WARN ("DoD TCP does not perform slow start");
return 0;
}
void
TcpRfc793::SetInitialCwnd (uint32_t cwnd)
{
NS_LOG_WARN ("DoD TCP does not have congestion window");
}
uint32_t
TcpRfc793::GetInitialCwnd (void) const
{
NS_LOG_WARN ("DoD TCP does not have congestion window");
return 0;
}
} // namespace ns3

View File

@@ -0,0 +1,61 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#ifndef TCP_RFC793_H
#define TCP_RFC793_H
#include "tcp-socket-base.h"
namespace ns3 {
/**
* \ingroup socket
* \ingroup tcp
*
* \brief An implementation of a stream socket using TCP.
*
* This class contains an RFC793 implementation of TCP, as well as a sockets
* interface for talking to TCP. This serves as a base for other TCP functions
* where the sliding window mechanism is handled here. This class provides
* connection orientation and sliding window flow control.
*/
class TcpRfc793 : public TcpSocketBase
{
public:
static TypeId GetTypeId (void);
/**
* Create an unbound tcp socket.
*/
TcpRfc793 (void);
TcpRfc793 (const TcpRfc793& sock);
virtual ~TcpRfc793 (void);
protected:
virtual Ptr<TcpSocketBase> Fork (); // Call CopyObject<TcpRfc793> to clone me
virtual void DupAck (const TcpHeader& t, uint32_t count);
virtual void SetSSThresh (uint32_t threshold);
virtual uint32_t GetSSThresh (void) const;
virtual void SetInitialCwnd (uint32_t cwnd);
virtual uint32_t GetInitialCwnd (void) const;
};
} // namespace ns3
#endif /* TCP_RFC793_H */

View File

@@ -0,0 +1,264 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#include "ns3/packet.h"
#include "ns3/fatal-error.h"
#include "ns3/log.h"
#include "tcp-rx-buffer.h"
NS_LOG_COMPONENT_DEFINE ("TcpRxBuffer");
namespace ns3 {
TypeId
TcpRxBuffer::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpRxBuffer")
.SetParent<Object> ()
.AddConstructor<TcpRxBuffer> ()
.AddTraceSource ("NextRxSequence",
"Next sequence number expected (RCV.NXT)",
MakeTraceSourceAccessor (&TcpRxBuffer::m_nextRxSeq))
;
return tid;
}
/* A user is supposed to create a TcpSocket through a factory. In TcpSocket,
* there are attributes SndBufSize and RcvBufSize to control the default Tx and
* Rx window sizes respectively, with default of 128 KiByte. The attribute
* RcvBufSize is passed to TcpRxBuffer by TcpSocketBase::SetRcvBufSize() and in
* turn, TcpRxBuffer:SetMaxBufferSize(). Therefore, the m_maxBuffer value
* initialized below is insignificant.
*/
TcpRxBuffer::TcpRxBuffer (uint32_t n)
: m_nextRxSeq(n), m_gotFin(false), m_size(0), m_maxBuffer(32768), m_availBytes(0)
{
}
TcpRxBuffer::~TcpRxBuffer ()
{
}
SequenceNumber32
TcpRxBuffer::NextRxSequence (void) const
{
return m_nextRxSeq;
}
void
TcpRxBuffer::SetNextRxSequence (const SequenceNumber32& s)
{
m_nextRxSeq = s;
}
uint32_t
TcpRxBuffer::MaxBufferSize (void) const
{
return m_maxBuffer;
}
void
TcpRxBuffer::SetMaxBufferSize (uint32_t s)
{
m_maxBuffer = s;
}
uint32_t
TcpRxBuffer::Size (void) const
{
return m_size;
}
uint32_t
TcpRxBuffer::Available () const
{
return m_availBytes;
}
void
TcpRxBuffer::IncNextRxSequence ()
{
NS_LOG_FUNCTION (this);
// Increment nextRxSeq is valid only if we don't have any data buffered,
// this is supposed to be called only during the three-way handshake
NS_ASSERT (m_size == 0);
m_nextRxSeq++;
}
// Return the highest sequence number that this TcpRxBuffer can accept
SequenceNumber32
TcpRxBuffer::MaxRxSequence (void) const
{
if (m_gotFin)
{ // No data allowed beyond FIN
return m_finSeq;
}
else if (m_data.size ())
{ // No data allowed beyond Rx window allowed
return m_data.begin()->first + SequenceNumber32 (m_maxBuffer);
}
return m_nextRxSeq + SequenceNumber32 (m_maxBuffer);
}
void
TcpRxBuffer::SetFinSequence (const SequenceNumber32& s)
{
NS_LOG_FUNCTION (this);
m_gotFin = true;
m_finSeq = s;
if (m_nextRxSeq == m_finSeq) ++m_nextRxSeq;
}
bool
TcpRxBuffer::Finished (void)
{
return (m_gotFin && m_finSeq < m_nextRxSeq);
}
bool
TcpRxBuffer::Add (Ptr<Packet> p, TcpHeader const& tcph)
{
NS_LOG_FUNCTION (this << p << tcph);
uint32_t pktSize = p->GetSize ();
SequenceNumber32 headSeq = tcph.GetSequenceNumber ();
SequenceNumber32 tailSeq = headSeq + SequenceNumber32 (pktSize);
NS_LOG_LOGIC ("Add pkt " << p << " len=" << pktSize << " seq=" << headSeq
<< ", when NextRxSeq=" << m_nextRxSeq << ", buffsize=" << m_size);
// Trim packet to fit Rx window specification
if (headSeq < m_nextRxSeq) headSeq = m_nextRxSeq;
if (m_data.size ())
{
SequenceNumber32 maxSeq = m_data.begin ()->first + SequenceNumber32 (m_maxBuffer);
if (maxSeq < tailSeq) tailSeq = maxSeq;
if (tailSeq < headSeq) headSeq = tailSeq;
}
// Remove overlapped bytes from packet
BufIterator i = m_data.begin ();
while (i != m_data.end () && i->first <= tailSeq)
{
SequenceNumber32 lastByteSeq = i->first + SequenceNumber32 (i->second->GetSize ());
if (lastByteSeq > headSeq)
{
if (i->first > headSeq && lastByteSeq < tailSeq)
{ // Rare case: Existing packet is embedded fully in the new packet
m_size -= i->second->GetSize();
m_data.erase (i++);
continue;
}
if (i->first <= headSeq)
{ // Incoming head is overlapped
headSeq = lastByteSeq;
}
if (lastByteSeq >= tailSeq)
{ // Incoming tail is overlapped
tailSeq = i->first;
}
}
++i;
}
// We now know how much we are going to store, trim the packet
if (headSeq >= tailSeq)
{
NS_LOG_LOGIC ("Nothing to buffer");
return false; // Nothing to buffer anyway
}
else
{
uint32_t start = headSeq - tcph.GetSequenceNumber ();
uint32_t length = tailSeq - headSeq;
p = p->CreateFragment (start, length);
NS_ASSERT (length == p->GetSize ());
}
// Insert packet into buffer
NS_ASSERT (m_data.find (headSeq) == m_data.end ()); // Shouldn't be there yet
m_data [ headSeq ] = p;
NS_LOG_LOGIC ("Buffered packet of seqno=" << headSeq << " len=" << p->GetSize ());
// Update variables
m_size += p->GetSize (); // Occupancy
for (BufIterator i = m_data.begin (); i != m_data.end (); ++i)
{
if (i->first < m_nextRxSeq)
{
continue;
}
else if (i->first > m_nextRxSeq)
{
break;
};
m_nextRxSeq = i->first + SequenceNumber32 (i->second->GetSize ());
m_availBytes += i->second->GetSize ();
}
NS_LOG_LOGIC ("Updated buffer occupancy=" << m_size << " nextRxSeq=" << m_nextRxSeq);
if (m_gotFin && m_nextRxSeq == m_finSeq)
{ // Account for the FIN packet
++m_nextRxSeq;
};
return true;
}
Ptr<Packet>
TcpRxBuffer::Extract (uint32_t maxSize)
{
NS_LOG_FUNCTION (this << maxSize);
uint32_t extractSize = std::min (maxSize, m_availBytes);
NS_LOG_LOGIC ("Requested to extract " << extractSize << " bytes from TcpRxBuffer of size=" << m_size);
if (extractSize == 0) return 0; // No contiguous block to return
NS_ASSERT (m_data.size ()); // At least we have something to extract
Ptr<Packet> outPkt = Create<Packet> (); // The packet that contains all the data to return
BufIterator i;
while (extractSize)
{ // Check the buffered data for delivery
i = m_data.begin ();
NS_ASSERT (i->first <= m_nextRxSeq); // in-sequence data expected
// Check if we send the whole pkt or just a partial
uint32_t pktSize = i->second->GetSize ();
if (pktSize <= extractSize)
{ // Whole packet is extracted
outPkt->AddAtEnd (i->second);
m_data.erase (i);
m_size -= pktSize;
m_availBytes -= pktSize;
extractSize -= pktSize;
}
else
{ // Partial is extracted and done
outPkt->AddAtEnd (i->second->CreateFragment (0, extractSize));
m_data[i->first + SequenceNumber32 (extractSize)] = i->second->CreateFragment (extractSize, pktSize - extractSize);
m_data.erase (i);
m_size -= extractSize;
m_availBytes -= extractSize;
extractSize = 0;
}
}
if (outPkt->GetSize () == 0)
{
NS_LOG_LOGIC ("Nothing extracted.");
return 0;
}
NS_LOG_LOGIC ("Extracted " << outPkt->GetSize( ) << " bytes, bufsize=" << m_size
<< ", num pkts in buffer=" << m_data.size ());
return outPkt;
}
} //namepsace ns3

View File

@@ -0,0 +1,89 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#ifndef __TCP_RX_BUFFER_H__
#define __TCP_RX_BUFFER_H__
#include <map>
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/sequence-number.h"
#include "ns3/ptr.h"
#include "ns3/tcp-header.h"
namespace ns3 {
class Packet;
/**
* \ingroup tcp
*
* \brief class for the reordering buffer that keeps the data from lower layer, i.e.
* TcpL4Protocol, sent to the application
*/
class TcpRxBuffer : public Object
{
public:
static TypeId GetTypeId (void);
TcpRxBuffer (uint32_t n = 0);
virtual ~TcpRxBuffer ();
// Accessors
SequenceNumber32 NextRxSequence (void) const;
SequenceNumber32 MaxRxSequence (void) const;
void IncNextRxSequence (void);
void SetNextRxSequence (const SequenceNumber32& s);
void SetFinSequence (const SequenceNumber32& s);
uint32_t MaxBufferSize (void) const;
void SetMaxBufferSize (uint32_t s);
uint32_t Size (void) const;
uint32_t Available () const;
bool Finished (void);
/**
* Insert a packet into the buffer and update the availBytes counter to
* reflect the number of bytes ready to send to the application. This
* function handles overlap by triming the head of the inputted packet and
* removing data from the buffer that overlaps the tail of the inputted
* packet
*
* \return True when success, false otherwise.
*/
bool Add (Ptr<Packet> p, TcpHeader const& tcph);
/**
* Extract data from the head of the buffer as indicated by nextRxSeq.
* The extracted data is going to be forwarded to the application.
*/
Ptr<Packet> Extract (uint32_t maxSize);
public:
typedef std::map<SequenceNumber32, Ptr<Packet> >::iterator BufIterator;
TracedValue<SequenceNumber32> m_nextRxSeq; //< Seqnum of the first missing byte in data (RCV.NXT)
SequenceNumber32 m_finSeq; //< Seqnum of the FIN packet
bool m_gotFin; //< Did I received FIN packet?
uint32_t m_size; //< Number of total data bytes in the buffer, not necessarily contiguous
uint32_t m_maxBuffer; //< Upper bound of the number of data bytes in buffer (RCV.WND)
uint32_t m_availBytes; //< Number of bytes available to read, i.e. contiguous block at head
std::map<SequenceNumber32, Ptr<Packet> > m_data;
//< Corresponding data (may be null)
};
}//namepsace ns3
#endif /* __TCP_RX_BUFFER_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,222 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#ifndef TCP_SOCKET_BASE_H
#define TCP_SOCKET_BASE_H
#include <stdint.h>
#include <queue>
#include "ns3/callback.h"
#include "ns3/traced-value.h"
#include "ns3/tcp-socket.h"
#include "ns3/ptr.h"
#include "ns3/ipv4-address.h"
#include "ns3/ipv4-header.h"
#include "ns3/ipv4-interface.h"
#include "ns3/event-id.h"
#include "tcp-tx-buffer.h"
#include "tcp-rx-buffer.h"
#include "rtt-estimator.h"
namespace ns3 {
class Ipv4EndPoint;
class Node;
class Packet;
class TcpL4Protocol;
class TcpHeader;
/**
* \ingroup socket
* \ingroup tcp
*
* \brief A base class for implementation of a stream socket using TCP.
*
* This class contains the essential components of TCP, as well as a sockets
* interface for upper layers to call. This serves as a base for other TCP
* functions where the sliding window mechanism is handled here. This class
* provides connection orientation and sliding window flow control. Part of
* this class is modified from the original NS-3 TCP socket implementation
* (TcpSocketImpl) by Raj Bhattacharjea.
*/
class TcpSocketBase : public TcpSocket
{
public:
static TypeId GetTypeId (void);
/**
* Create an unbound TCP socket
*/
TcpSocketBase (void);
/**
* Clone a TCP socket, for use upon receiving a connection request in LISTEN state
*/
TcpSocketBase (const TcpSocketBase& sock);
virtual ~TcpSocketBase (void);
// Set associated Node, TcpL4Protocol, RttEstimator to this socket
virtual void SetNode (Ptr<Node> node);
virtual void SetTcp (Ptr<TcpL4Protocol> tcp);
virtual void SetRtt (Ptr<RttEstimator> rtt);
// Necessary implementations of null functions from ns3::Socket
virtual enum SocketErrno GetErrno (void) const; // returns m_errno
virtual enum SocketType GetSocketType (void) const;// returns socket type
virtual Ptr<Node> GetNode (void) const; // returns m_node
virtual int Bind (void); // Bind a socket by setting up endpoint in TcpL4Protocol
virtual int Bind (const Address &address); // ... endpoint of specific addr or port
virtual int Connect (const Address &address); // Setup endpoint and call ProcessAction() to connect
virtual int Listen (void); // Verify the socket is in a correct state and call ProcessAction() to listen
virtual int Close (void); // Close by app: Kill socket upon tx buffer emptied
virtual int ShutdownSend (void); // Assert the m_shutdownSend flag to prevent send to network
virtual int ShutdownRecv (void); // Assert the m_shutdownRecv flag to prevent forward to app
virtual int Send (Ptr<Packet> p, uint32_t flags); // Call by app to send data to network
virtual int SendTo (Ptr<Packet> p, uint32_t flags, const Address &toAddress); // Same as Send(), toAddress is insignificant
virtual Ptr<Packet> Recv (uint32_t maxSize, uint32_t flags); // Return a packet to be forwarded to app
virtual Ptr<Packet> RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress); // ... and write the remote address at fromAddress
virtual uint32_t GetTxAvailable (void) const; // Available Tx buffer size
virtual uint32_t GetRxAvailable (void) const; // Available-to-read data size, i.e. value of m_rxAvailable
virtual int GetSockName (Address &address) const; // Return local addr:port in address
virtual void BindToNetDevice (Ptr<NetDevice> netdevice); // NetDevice with my m_endPoint
protected:
// Implementing ns3::TcpSocket -- Attribute get/set
virtual void SetSndBufSize (uint32_t size);
virtual uint32_t GetSndBufSize (void) const;
virtual void SetRcvBufSize (uint32_t size);
virtual uint32_t GetRcvBufSize (void) const;
virtual void SetSegSize (uint32_t size);
virtual uint32_t GetSegSize (void) const;
virtual void SetSSThresh (uint32_t threshold) = 0;
virtual uint32_t GetSSThresh (void) const = 0;
virtual void SetInitialCwnd (uint32_t cwnd) = 0;
virtual uint32_t GetInitialCwnd (void) const = 0;
virtual void SetConnTimeout (Time timeout);
virtual Time GetConnTimeout (void) const;
virtual void SetConnCount (uint32_t count);
virtual uint32_t GetConnCount (void) const;
virtual void SetDelAckTimeout (Time timeout);
virtual Time GetDelAckTimeout (void) const;
virtual void SetDelAckMaxCount (uint32_t count);
virtual uint32_t GetDelAckMaxCount (void) const;
virtual void SetPersistTimeout (Time timeout);
virtual Time GetPersistTimeout (void) const;
virtual bool SetAllowBroadcast (bool allowBroadcast);
virtual bool GetAllowBroadcast () const;
// Helper functions: Connection set up
int SetupCallback (void); // Common part of the two Bind(), i.e. set callback and remembering local addr:port
int DoConnect (void); // Sending a SYN packet to make a connection if the state allows
void ConnectionSucceeded (void); // Schedule-friendly wrapper for Socket::NotifyConnectionSucceeded()
int SetupEndpoint (void); // Configure m_endpoint for local addr for given remote addr
void CompleteFork (Ptr<Packet>, const TcpHeader&, const Address& fromAddress, const Address& toAdress);
// Helper functions: Transfer operation
void ForwardUp (Ptr<Packet> packet, Ipv4Header header, uint16_t port, Ptr<Ipv4Interface> incomingInterface); //Get a pkt from L3
bool SendPendingData (bool withAck = false); // Send as much as the window allows
void SendEmptyPacket (uint8_t flags); // Send a empty packet that carries a flag, e.g. ACK
void SendRST (void); // Send reset and tear down this socket
bool OutOfRange (SequenceNumber32 s) const; // Check if a sequence number is within rx window
// Helper functions: Connection close
int DoClose (void); // Close a socket by sending RST, FIN, or FIN+ACK, depend on the current state
void CloseAndNotify (void); // To CLOSED state, notify upper layer, and deallocate end point
void Destroy (void); // Kill this socket by zeroing its attributes
void DeallocateEndPoint (void); // Deallocate m_endPoint
void PeerClose (Ptr<Packet>, const TcpHeader&); // Received a FIN from peer, notify rx buffer
void DoPeerClose (void); // FIN is in sequence, notify app and respond with a FIN
void CancelAllTimers (void); // Cancel all timer when endpoint is deleted
// State transition functions
void ProcessEstablished (Ptr<Packet>, const TcpHeader&); // Received a packet upon ESTABLISHED state
void ProcessListen (Ptr<Packet>, const TcpHeader&, const Address&, const Address&); // Process the newly received ACK
void ProcessSynSent (Ptr<Packet>, const TcpHeader&); // Received a packet upon SYN_SENT
void ProcessSynRcvd (Ptr<Packet>, const TcpHeader&, const Address&, const Address&); // Received a packet upon SYN_RCVD
void ProcessWait (Ptr<Packet>, const TcpHeader&); // Received a packet upon CLOSE_WAIT, FIN_WAIT_1, FIN_WAIT_2
void ProcessClosing (Ptr<Packet>, const TcpHeader&); // Received a packet upon CLOSING
void ProcessLastAck (Ptr<Packet>, const TcpHeader&); // Received a packet upon LAST_ACK
// Window management
virtual uint32_t UnAckDataCount (void); // Return count of number of unacked bytes
virtual uint32_t BytesInFlight (void); // Return total bytes in flight
virtual uint32_t Window (void); // Return the max possible number of unacked bytes
virtual uint32_t AvailableWindow (void); // Return unfilled portion of window
virtual uint16_t AdvertisedWindowSize (void); // The amount of Rx window announced to the peer
// Manage data tx/rx
virtual Ptr<TcpSocketBase> Fork (void) = 0; // Call CopyObject<> to clone me
virtual void ReceivedAck (Ptr<Packet>, const TcpHeader&); // Received an ACK packet
virtual void ReceivedData (Ptr<Packet>, const TcpHeader&); // Recv of a data, put into buffer, call L7 to get it if necessary
virtual void EstimateRtt (const TcpHeader&); // RTT accounting
virtual void NewAck (SequenceNumber32 const& seq); // Update buffers w.r.t. ACK
virtual void DupAck (const TcpHeader& t, uint32_t count) = 0; // Received dupack
virtual void ReTxTimeout (void); // Call Retransmit() upon RTO event
virtual void Retransmit (void); // Halving cwnd and call DoRetransmit()
virtual void DelAckTimeout (void); // Action upon delay ACK timeout, i.e. send an ACK
virtual void LastAckTimeout (void); // Timeout at LAST_ACK, close the connection
virtual void PersistTimeout (void); // Send 1 byte probe to get an updated window size
virtual void DoRetransmit (void); // Retransmit the oldest packet
protected:
// Counters and events
EventId m_retxEvent; //< Retransmission event
EventId m_lastAckEvent; //< Last ACK timeout event
EventId m_delAckEvent; //< Delayed ACK timeout event
EventId m_persistEvent; //< Persist event: Send 1 byte to probe for a non-zero Rx window
uint32_t m_dupAckCount; //< Dupack counter
uint32_t m_delAckCount; //< Delayed ACK counter
uint32_t m_delAckMaxCount; //< Number of packet to fire an ACK before delay timeout
uint32_t m_cnCount; //< Count of remaining connection retries
TracedValue<Time> m_rto; //< Retransmit timeout
TracedValue<Time> m_lastRtt; //< Last RTT sample collected
Time m_delAckTimeout; //< Time to delay an ACK
Time m_persistTimeout; //< Time between sending 1-byte probes
Time m_cnTimeout; //< Timeout for connection retry
// Connections to other layers of TCP/IP
Ipv4EndPoint* m_endPoint;
Ptr<Node> m_node;
Ptr<TcpL4Protocol> m_tcp;
// Round trip time estimation
Ptr<RttEstimator> m_rtt;
// Rx and Tx buffer management
TracedValue<SequenceNumber32> m_nextTxSequence; //< Next seqnum to be sent (SND.NXT), ReTx pushes it back
TracedValue<SequenceNumber32> m_highTxMark; //< Highest seqno ever sent, regardless of ReTx
TcpRxBuffer m_rxBuffer; //< Rx buffer (reordering buffer)
TcpTxBuffer m_txBuffer; //< Tx buffer
// State-related attributes
TracedValue<TcpStates_t> m_state; //< TCP state
enum SocketErrno m_errno; //< Socket error code
bool m_closeNotified; //< Told app to close socket
bool m_closeOnEmpty; //< Close socket upon tx buffer emptied
bool m_shutdownSend; //< Send no longer allowed
bool m_shutdownRecv; //< Receive no longer allowed
bool m_connected; //< Connection established
// Window management
uint32_t m_segmentSize; //< Segment size
TracedValue<uint32_t> m_rWnd; //< Flow control window at remote side
};
} // namespace ns3
#endif /* TCP_SOCKET_BASE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,254 +0,0 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 Georgia Tech Research Corporation
*
* 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
*
* Author: Raj Bhattacharjea <raj.b@gatech.edu>
*/
#ifndef TCP_SOCKET_IMPL_H
#define TCP_SOCKET_IMPL_H
#include <stdint.h>
#include <queue>
#include "ns3/callback.h"
#include "ns3/traced-value.h"
#include "ns3/tcp-socket.h"
#include "ns3/ptr.h"
#include "ns3/ipv4-address.h"
#include "ns3/event-id.h"
#include "ns3/ipv4-header.h"
#include "ipv4-interface.h"
#include "tcp-typedefs.h"
#include "pending-data.h"
#include "ns3/sequence-number.h"
#include "rtt-estimator.h"
namespace ns3 {
class Ipv4EndPoint;
class Node;
class Packet;
class TcpL4Protocol;
class TcpHeader;
/**
* \ingroup socket
* \ingroup tcp
*
* \brief An implementation of a stream socket using TCP.
*
* This class contains an implementation of TCP Tahoe, as well as a sockets
* interface for talking to TCP. Features include connection orientation,
* reliability through cumulative acknowledgements, congestion and flow
* control. Finite send buffer semantics are modeled, but as of yet, finite
* receive buffer modelling is unimplemented.
*
* The closedown of these sockets is as of yet not compliant with the relevant
* RFCs, i.e. the FIN handshaking isn't correct. While this is visible at the
* PCAP tracing level, it has no effect on the statistics users are interested
* in, i.e. throughput, delay, etc. of actual payload data.
*
* Asynchronous callbacks to provide notifications to higher layers that a
* protocol event has occured, such as space freeing up in the send buffer
* or new data arriving in the receive buffer.
*/
class TcpSocketImpl : public TcpSocket
{
public:
static TypeId GetTypeId (void);
/**
* Create an unbound tcp socket.
*/
TcpSocketImpl ();
TcpSocketImpl (const TcpSocketImpl& sock);
virtual ~TcpSocketImpl ();
void SetNode (Ptr<Node> node);
void SetTcp (Ptr<TcpL4Protocol> tcp);
void SetRtt (Ptr<RttEstimator> rtt);
virtual enum SocketErrno GetErrno (void) const;
virtual enum SocketType GetSocketType (void) const;
virtual Ptr<Node> GetNode (void) const;
virtual int Bind (void);
virtual int Bind (const Address &address);
virtual int Close (void);
virtual int ShutdownSend (void);
virtual int ShutdownRecv (void);
virtual int Connect(const Address &address);
virtual int Listen(void);
virtual uint32_t GetTxAvailable (void) const;
virtual int Send (Ptr<Packet> p, uint32_t flags);
virtual int SendTo(Ptr<Packet> p, uint32_t flags, const Address &toAddress);
virtual uint32_t GetRxAvailable (void) const;
virtual Ptr<Packet> Recv (uint32_t maxSize, uint32_t flags);
virtual Ptr<Packet> RecvFrom (uint32_t maxSize, uint32_t flags,
Address &fromAddress);
virtual int GetSockName (Address &address) const;
virtual void BindToNetDevice (Ptr<NetDevice> netdevice);
virtual bool SetAllowBroadcast (bool allowBroadcast);
virtual bool GetAllowBroadcast () const;
private:
friend class Tcp;
// invoked by Tcp class
int FinishBind (void);
void ForwardUp (Ptr<Packet> p, Ipv4Header header, uint16_t port,
Ptr<Ipv4Interface> incomingInterface);
void Destroy (void);
int DoSendTo (Ptr<Packet> p, const Address &daddr);
int DoSendTo (Ptr<Packet> p, Ipv4Address daddr, uint16_t dport);
void SendEmptyPacket(uint8_t flags);
void SendRST();
//methods for state
bool ProcessAction (Actions_t a);
bool ProcessAction (Actions_t a, const TcpHeader& tcpHeader,
Ipv4Address saddr, Ipv4Address daddr);
bool ProcessPacketAction (Actions_t a, Ptr<Packet> p,
const TcpHeader& tcpHeader,
const Address& fromAddress,
const Address& toAddress);
Actions_t ProcessEvent (Events_t e);
bool SendPendingData(bool withAck = false);
void CompleteFork(Ptr<Packet>, const TcpHeader&, const Address& fromAddress, const Address& toAddress);
void ConnectionSucceeded();
//methods for window management
virtual uint32_t UnAckDataCount(); // Return count of number of unacked bytes
virtual uint32_t BytesInFlight(); // Return total bytes in flight
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& fromAddress, const Address& toAddress);
void RxBufFinishInsert (SequenceNumber32);
Ptr<TcpSocketImpl> Copy ();
virtual void NewAck (SequenceNumber32 seq);
virtual void DupAck (const TcpHeader& t, uint32_t count);
virtual void ReTxTimeout ();
void DelAckTimeout ();
void LastAckTimeout ();
void PersistTimeout ();
void Retransmit ();
void CommonNewAck (SequenceNumber32 seq, bool skipTimer = false);
// All timers are cancelled when the endpoint is deleted, to insure
// we don't have additional activity
void CancelAllTimers();
// attribute related
virtual void SetSndBufSize (uint32_t size);
virtual uint32_t GetSndBufSize (void) const;
virtual void SetRcvBufSize (uint32_t size);
virtual uint32_t GetRcvBufSize (void) const;
virtual void SetSegSize (uint32_t size);
virtual uint32_t GetSegSize (void) const;
virtual void SetSSThresh (uint32_t threshold);
virtual uint32_t GetSSThresh (void) const;
virtual void SetInitialCwnd (uint32_t cwnd);
virtual uint32_t GetInitialCwnd (void) const;
virtual void SetConnTimeout (Time timeout);
virtual Time GetConnTimeout (void) const;
virtual void SetConnCount (uint32_t count);
virtual uint32_t GetConnCount (void) const;
virtual void SetDelAckTimeout (Time timeout);
virtual Time GetDelAckTimeout (void) const;
virtual void SetDelAckMaxCount (uint32_t count);
virtual uint32_t GetDelAckMaxCount (void) const;
bool m_skipRetxResched;
uint32_t m_dupAckCount;
EventId m_retxEvent;
EventId m_lastAckEvent;
EventId m_delAckEvent;
uint32_t m_delAckCount;
uint32_t m_delAckMaxCount;
Time m_delAckTimeout;
Ipv4EndPoint *m_endPoint;
Ptr<Node> m_node;
Ptr<TcpL4Protocol> m_tcp;
enum SocketErrno m_errno;
bool m_shutdownSend;
bool m_shutdownRecv;
bool m_connected;
//manage the state information
States_t m_state;
bool m_closeNotified;
bool m_closeRequestNotified;
bool m_closeOnEmpty;
bool m_pendingClose;
//sequence info, sender side
SequenceNumber32 m_nextTxSequence;
SequenceNumber32 m_highTxMark;
SequenceNumber32 m_highestRxAck;
SequenceNumber32 m_lastRxAck;
//sequence info, receiver side
SequenceNumber32 m_nextRxSequence; //next expected sequence
//sequence number where fin was sent or received
SequenceNumber32 m_finSequence;
//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;
SequenceNumber32 m_firstPendingSequence;
// Window management
uint32_t m_segmentSize; //SegmentSize
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;
// Timer-related members
Time m_cnTimeout;
uint32_t m_cnCount;
// Attributes
uint32_t m_sndBufSize; // buffer limit for the outgoing queue
uint32_t m_rxBufMaxSize; // maximum receive socket buffer size
};
}//namespace ns3
#endif /* TCP_SOCKET_IMPL_H */

View File

@@ -0,0 +1,190 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#define NS_LOG_APPEND_CONTEXT \
if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
#include "tcp-tahoe.h"
#include "ns3/log.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/simulator.h"
#include "ns3/abort.h"
#include "ns3/node.h"
NS_LOG_COMPONENT_DEFINE ("TcpTahoe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (TcpTahoe);
TypeId
TcpTahoe::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpTahoe")
.SetParent<TcpSocketBase> ()
.AddConstructor<TcpTahoe> ()
.AddTraceSource ("CongestionWindow",
"The TCP connection's congestion window",
MakeTraceSourceAccessor (&TcpTahoe::m_cWnd))
;
return tid;
}
TcpTahoe::TcpTahoe (void) : m_initialCWnd (0)
{
NS_LOG_FUNCTION (this);
}
TcpTahoe::TcpTahoe (const TcpTahoe& sock)
: TcpSocketBase (sock),
m_cWnd (sock.m_cWnd),
m_ssThresh (sock.m_ssThresh),
m_initialCWnd (sock.m_initialCWnd)
{
NS_LOG_FUNCTION (this);
NS_LOG_LOGIC ("Invoked the copy constructor");
}
TcpTahoe::~TcpTahoe (void)
{
}
void
TcpTahoe::SetNode (Ptr<Node> node)
{
TcpSocketBase::SetNode (node);
/*
* Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must
* not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and
* m_segmentSize are set by the attribute system in ns3::TcpSocket.
*/
m_cWnd = m_initialCWnd * m_segmentSize;
}
/** Limit the size of in-flight data by cwnd and receiver's rxwin */
uint32_t
TcpTahoe::Window (void)
{
NS_LOG_FUNCTION (this);
return std::min (m_rWnd.Get (), m_cWnd.Get ());
}
Ptr<TcpSocketBase>
TcpTahoe::Fork (void)
{
return CopyObject<TcpTahoe> (this);
}
/** New ACK (up to seqnum seq) received. Increase cwnd and call TcpSocketBase::NewAck() */
void
TcpTahoe::NewAck (SequenceNumber32 const& seq)
{
NS_LOG_FUNCTION (this << seq);
NS_LOG_LOGIC ("TcpTahoe receieved ACK for seq " << seq <<
" cwnd " << m_cWnd <<
" ssthresh " << m_ssThresh);
if (m_cWnd < m_ssThresh)
{ // Slow start mode, add one segSize to cWnd. Default m_ssThresh is 65535. (RFC2001, sec.1)
m_cWnd += m_segmentSize;
NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
}
else
{ // Congestion avoidance mode, increase by (segSize*segSize)/cwnd. (RFC2581, sec.3.1)
// To increase cwnd for one segSize per RTT, it should be (ackBytes*segSize)/cwnd
double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get ();
adder = std::max (1.0, adder);
m_cWnd += static_cast<uint32_t> (adder);
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
}
TcpSocketBase::NewAck (seq); // Complete newAck processing
}
/** Cut down ssthresh upon triple dupack */
void
TcpTahoe::DupAck (const TcpHeader& t, uint32_t count)
{
NS_LOG_FUNCTION (this << "t " << count);
if (count == 3)
{ // triple duplicate ack triggers fast retransmit (RFC2001, sec.3)
NS_LOG_INFO ("Triple Dup Ack: old ssthresh " << m_ssThresh << " cwnd " << m_cWnd);
// fast retransmit in Tahoe means triggering RTO earlier. Tx is restarted
// from the highest ack and run slow start again.
// (Fall & Floyd 1996, sec.1)
m_ssThresh = std::max (static_cast<unsigned> (m_cWnd / 2), m_segmentSize * 2); // Half ssthresh
m_cWnd = m_segmentSize; // Run slow start again
m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack
NS_LOG_INFO ("Triple Dup Ack: new ssthresh " << m_ssThresh << " cwnd " << m_cWnd);
NS_LOG_LOGIC ("Triple Dup Ack: retransmit missing segment at " << Simulator::Now ().GetSeconds ());
DoRetransmit ();
}
}
/** Retransmit timeout */
void TcpTahoe::Retransmit (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
// If erroneous timeout in closed/timed-wait state, just return
if (m_state == CLOSED || m_state == TIME_WAIT) return;
// If all data are received, just return
if (m_txBuffer.HeadSequence () >= m_nextTxSequence) return;
m_ssThresh = std::max (static_cast<unsigned> (m_cWnd / 2), m_segmentSize * 2); // Half ssthresh
m_cWnd = m_segmentSize; // Set cwnd to 1 segSize (RFC2001, sec.2)
m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack
m_rtt->IncreaseMultiplier (); // Double the next RTO
DoRetransmit (); // Retransmit the packet
}
void
TcpTahoe::SetSegSize (uint32_t size)
{
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpTahoe::SetSegSize() cannot change segment size after connection started.");
m_segmentSize = size;
m_cWnd = m_initialCWnd * m_segmentSize;
}
void
TcpTahoe::SetSSThresh (uint32_t threshold)
{
m_ssThresh = threshold;
}
uint32_t
TcpTahoe::GetSSThresh (void) const
{
return m_ssThresh;
}
void
TcpTahoe::SetInitialCwnd (uint32_t cwnd)
{
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpTahoe::SetInitialCwnd() cannot change initial cwnd after connection started.");
m_initialCWnd = cwnd;
m_cWnd = m_initialCWnd * m_segmentSize;
}
uint32_t
TcpTahoe::GetInitialCwnd (void) const
{
return m_initialCWnd;
}
} // namespace ns3

View File

@@ -0,0 +1,78 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#ifndef TCP_TAHOE_H
#define TCP_TAHOE_H
#include "tcp-socket-base.h"
namespace ns3 {
/**
* \ingroup socket
* \ingroup tcp
*
* \brief An implementation of a stream socket using TCP.
*
* This class contains the Tahoe implementation of TCP. Tahoe is not officially
* published in RFC. The reference for implementing this is based on
* Kevin Fall and Sally Floyd, "Simulation-based Comparisons of Tahoe, Reno, and SACK TCP", CCR, 1996
* http://inst.eecs.berkeley.edu/~ee122/fa05/projects/Project2/proj2_spec_files/sacks.pdf
* In summary, we have slow start, congestion avoidance, and fast retransmit.
* The implementation of these algorithms are based on W. R. Stevens's book and
* also RFC2001.
*/
class TcpTahoe : public TcpSocketBase
{
public:
static TypeId GetTypeId (void);
/**
* Create an unbound tcp socket.
*/
TcpTahoe (void);
TcpTahoe (const TcpTahoe& sock);
virtual ~TcpTahoe (void);
// Set associated Node, TcpL4Protocol, RttEstimator to this socket
virtual void SetNode (Ptr<Node> node);
protected:
virtual uint32_t Window (void); // Return the max possible number of unacked bytes
virtual Ptr<TcpSocketBase> Fork (void); // Call CopyObject<TcpTahoe> to clone me
virtual void NewAck (SequenceNumber32 const& seq); // Inc cwnd and call NewAck() of parent
virtual void DupAck (const TcpHeader& t, uint32_t count); // Treat 3 dupack as timeout
virtual void Retransmit (void); // Retransmit time out
// Implementing ns3::TcpSocket -- Attribute get/set
virtual void SetSegSize (uint32_t size);
virtual void SetSSThresh (uint32_t threshold);
virtual uint32_t GetSSThresh (void) const;
virtual void SetInitialCwnd (uint32_t cwnd);
virtual uint32_t GetInitialCwnd (void) const;
protected:
TracedValue<uint32_t> m_cWnd; //< Congestion window
uint32_t m_ssThresh; //< Slow Start Threshold
uint32_t m_initialCWnd; //< Initial cWnd value
};
} // namespace ns3
#endif /* TCP_TAHOE_H */

View File

@@ -0,0 +1,250 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#include <iostream>
#include <algorithm>
#include <string.h>
#include "ns3/packet.h"
#include "ns3/fatal-error.h"
#include "ns3/log.h"
#include "tcp-tx-buffer.h"
NS_LOG_COMPONENT_DEFINE ("TcpTxBuffer");
namespace ns3 {
TypeId
TcpTxBuffer::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpTxBuffer")
.SetParent<Object> ()
.AddConstructor<TcpTxBuffer> ()
.AddTraceSource ("UnackSequence",
"First unacknowledged sequence number (SND.UNA)",
MakeTraceSourceAccessor (&TcpTxBuffer::m_firstByteSeq))
;
return tid;
}
/* A user is supposed to create a TcpSocket through a factory. In TcpSocket,
* there are attributes SndBufSize and RcvBufSize to control the default Tx and
* Rx window sizes respectively, with default of 128 KiByte. The attribute
* SndBufSize is passed to TcpTxBuffer by TcpSocketBase::SetSndBufSize() and in
* turn, TcpTxBuffer:SetMaxBufferSize(). Therefore, the m_maxBuffer value
* initialized below is insignificant.
*/
TcpTxBuffer::TcpTxBuffer (uint32_t n)
: m_firstByteSeq(n), m_size (0), m_maxBuffer(32768), m_data (0)
{
}
TcpTxBuffer::~TcpTxBuffer (void)
{
}
SequenceNumber32
TcpTxBuffer::HeadSequence (void) const
{
return m_firstByteSeq;
}
SequenceNumber32
TcpTxBuffer::TailSequence (void) const
{
return m_firstByteSeq + SequenceNumber32 (m_size);
}
uint32_t
TcpTxBuffer::Size (void) const
{
return m_size;
}
uint32_t
TcpTxBuffer::MaxBufferSize (void) const
{
return m_maxBuffer;
}
void
TcpTxBuffer::SetMaxBufferSize (uint32_t n)
{
m_maxBuffer = n;
}
uint32_t
TcpTxBuffer::Available (void) const
{
return m_maxBuffer - m_size;
}
bool
TcpTxBuffer::Add (Ptr<Packet> p)
{
NS_LOG_FUNCTION (this << p);
NS_LOG_LOGIC ("Packet of size " << p->GetSize () << " appending to window starting at "
<< m_firstByteSeq << ", availSize="<< Available ());
if (p->GetSize () <= Available ())
{
if (p->GetSize () > 0)
{
m_data.push_back (p);
m_size += p->GetSize ();
NS_LOG_LOGIC ("Updated size=" << m_size << ", lastSeq=" << m_firstByteSeq + SequenceNumber32 (m_size));
}
return true;
}
NS_LOG_LOGIC ("Rejected. Not enough room to buffer packet.");
return false;
}
uint32_t
TcpTxBuffer::SizeFromSequence (const SequenceNumber32& seq) const
{
NS_LOG_FUNCTION (this << seq);
// Sequence of last byte in buffer
SequenceNumber32 lastSeq = m_firstByteSeq + SequenceNumber32 (m_size);
// Non-negative size
NS_LOG_LOGIC ("HeadSeq=" << m_firstByteSeq << ", lastSeq=" << lastSeq << ", size=" << m_size <<
", returns " << lastSeq - seq);
return lastSeq - seq;
}
Ptr<Packet>
TcpTxBuffer::CopyFromSequence (uint32_t numBytes, const SequenceNumber32& seq)
{
NS_LOG_FUNCTION (this << numBytes << seq);
uint32_t s = std::min (numBytes, SizeFromSequence (seq)); // Real size to extract. Insure not beyond end of data
if (s == 0)
{
return Create<Packet> (); // Empty packet returned
}
if (m_data.size () == 0)
{ // No actual data, just return dummy-data packet of correct size
return Create<Packet> (s);
}
// Extract data from the buffer and return
uint32_t offset = seq - m_firstByteSeq.Get ();
uint32_t count = 0; // Offset of the first byte of a packet in the buffer
uint32_t pktSize = 0;
bool beginFound = false;
int pktCount = 0;
Ptr<Packet> outPacket;
NS_LOG_LOGIC ("There are " << m_data.size () << " number of packets in buffer");
for (BufIterator i = m_data.begin (); i != m_data.end (); ++i)
{
pktCount++;
pktSize = (*i)->GetSize ();
if (!beginFound)
{ // Look for first fragment
if (count + pktSize > offset)
{
NS_LOG_LOGIC ("First byte found in packet #" << pktCount << " at buffer offset " << count
<< ", packet len=" << pktSize);
beginFound = true;
uint32_t packetOffset = offset - count;
uint32_t fragmentLength = count + pktSize - offset;
if (fragmentLength >= s)
{ // Data to be copied falls entirely in this packet
return (*i)->CreateFragment (packetOffset, s);
}
else
{ // This packet only fulfills part of the request
outPacket = (*i)->CreateFragment (packetOffset, fragmentLength);
}
NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
}
}
else if (count + pktSize >= offset + s)
{ // Last packet fragment found
NS_LOG_LOGIC ("Last byte found in packet #" << pktCount << " at buffer offset " << count
<< ", packet len=" << pktSize);
uint32_t fragmentLength = offset + s - count;
Ptr<Packet> endFragment = (*i)->CreateFragment (0, fragmentLength);
outPacket->AddAtEnd (endFragment);
NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
break;
}
else
{
NS_LOG_LOGIC ("Appending to output the packet #" << pktCount << " of offset " << count << " len=" << pktSize);
outPacket->AddAtEnd (*i);
NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
}
count += pktSize;
}
NS_ASSERT (outPacket->GetSize () == s);
return outPacket;
}
void
TcpTxBuffer::SetHeadSequence (const SequenceNumber32& seq)
{
NS_LOG_FUNCTION (this << seq);
m_firstByteSeq = seq;
}
void
TcpTxBuffer::DiscardUpTo (const SequenceNumber32& seq)
{
NS_LOG_FUNCTION (this << seq);
NS_LOG_LOGIC ("current data size=" << m_size << ", headSeq=" << m_firstByteSeq << ", maxBuffer=" << m_maxBuffer
<< ", numPkts=" << m_data.size ());
// Cases do not need to scan the buffer
if (m_firstByteSeq >= seq) return;
// Scan the buffer and discard packets
uint32_t offset = seq - m_firstByteSeq.Get (); // Number of bytes to remove
uint32_t pktSize;
NS_LOG_LOGIC ("Offset=" << offset);
BufIterator i = m_data.begin ();
while (i != m_data.end ())
{
if (offset > (*i)->GetSize ())
{ // This packet is behind the seqnum. Remove this packet from the buffer
pktSize = (*i)->GetSize ();
m_size -= pktSize;
offset -= pktSize;
m_firstByteSeq += pktSize;
i = m_data.erase (i);
NS_LOG_LOGIC ("Removed one packet of size " << pktSize << ", offset=" << offset);
}
else if (offset > 0)
{ // Part of the packet is behind the seqnum. Fragment
pktSize = (*i)->GetSize () - offset;
*i = (*i)->CreateFragment (offset, pktSize);
m_size -= offset;
m_firstByteSeq += offset;
NS_LOG_LOGIC ("Fragmented one packet by size " << offset << ", new size=" << pktSize);
break;
}
}
// Catching the case of ACKing a FIN
if (m_size == 0)
{
m_firstByteSeq = seq;
}
NS_LOG_LOGIC ("size=" << m_size << " headSeq=" << m_firstByteSeq << " maxBuffer=" << m_maxBuffer
<<" numPkts="<< m_data.size ());
NS_ASSERT (m_firstByteSeq == seq);
}
} // namepsace ns3

View File

@@ -0,0 +1,121 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* 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
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#ifndef __TCP_TX_BUFFER_H__
#define __TCP_TX_BUFFER_H__
#include <list>
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/object.h"
#include "ns3/sequence-number.h"
#include "ns3/ptr.h"
namespace ns3 {
class Packet;
/**
* \ingroup tcp
*
* \brief class for keeping the data sent by the application to the TCP socket, i.e.
* the sending buffer.
*/
class TcpTxBuffer : public Object
{
public:
static TypeId GetTypeId (void);
TcpTxBuffer (uint32_t n = 0);
virtual ~TcpTxBuffer (void);
// Accessors
/**
* Returns the first byte's sequence number
*/
SequenceNumber32 HeadSequence (void) const;
/**
* Returns the last byte's sequence number + 1
*/
SequenceNumber32 TailSequence (void) const;
/**
* Returns total number of bytes in this Tx buffer
*/
uint32_t Size (void) const;
/**
* Returns the Tx window size
*/
uint32_t MaxBufferSize (void) const;
/**
* Set the Tx window size
*/
void SetMaxBufferSize (uint32_t n);
/**
* Returns the available capacity in this Tx window
*/
uint32_t Available (void) const;
/**
* Append a data packet to the end of the buffer
*
* \param p The packet to be appended to the Tx buffer
* \return Boolean to indicate success
*/
bool Add (Ptr<Packet> p);
/**
* Returns the number of bytes from the buffer in the range [seq, tailSequence)
*/
uint32_t SizeFromSequence (const SequenceNumber32& seq) const;
/**
* Copy data of size numBytes into a packet, data from the range [seq, seq+numBytes)
*/
Ptr<Packet> CopyFromSequence (uint32_t numBytes, const SequenceNumber32& seq);
/**
* Set the m_firstByteSeq to seq. Supposed to be called only when the
* connection is just set up and we did not send any data out yet.
*/
void SetHeadSequence (const SequenceNumber32& seq);
/**
* Discard data up to but not including this sequence number.
*
* \param seq The sequence number of the head byte
*/
void DiscardUpTo (const SequenceNumber32& seq);
private:
typedef std::list<Ptr<Packet> >::iterator BufIterator;
TracedValue<SequenceNumber32> m_firstByteSeq; //< Sequence number of the first byte in data (SND.UNA)
uint32_t m_size; //< Number of data bytes
uint32_t m_maxBuffer; //< Max number of data bytes in buffer (SND.WND)
std::list<Ptr<Packet> > m_data; //< Corresponding data (may be null)
};
} // namepsace ns3
#endif

View File

@@ -1,112 +0,0 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 Georgia Tech Research Corporation
*
* 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
*
* Author: Raj Bhattacharjea <raj.b@gatech.edu>
* typedefs for tcp state machine
*/
#include <vector>
#include <map>
#include "ns3/sequence-number.h"
#ifndef TCP_TYPEDEFS_H
#define TCP_TYPEDEFS_H
namespace ns3 {
typedef enum { MAX_FLAGS = 0x40 } TCPMaxFlags_t; // Flags are 6 bits
typedef enum {
CLOSED, // 0
LISTEN, // 1
SYN_SENT, // 2
SYN_RCVD, // 3
ESTABLISHED, // 4
CLOSE_WAIT, // 5
LAST_ACK, // 6
FIN_WAIT_1, // 7
FIN_WAIT_2, // 8
CLOSING, // 9
TIMED_WAIT, // 10
LAST_STATE } States_t;
typedef enum {
APP_LISTEN, // 0
APP_CONNECT, // 1
APP_SEND, // 2
SEQ_RECV, // 3
APP_CLOSE, // 4
TIMEOUT, // 5
ACK_RX, // 6
SYN_RX, // 7
SYN_ACK_RX, // 8
FIN_RX, // 9
FIN_ACK_RX, // 10
FIN_ACKED, // 11
RST_RX, // 12
BAD_FLAGS, // 13
LAST_EVENT } Events_t;
typedef enum {
NO_ACT, // 0
ACK_TX, // 1
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
{
public:
SA () : state (LAST_STATE), action (LAST_ACTION) { }
SA (States_t s, Actions_t a) : state (s), action (a) { }
public:
States_t state;
Actions_t action;
};
typedef std::vector<SA> StateActionVec_t;
typedef std::vector<StateActionVec_t> StateActions_t; // One per current state
typedef std::vector<Events_t> EventVec_t; // For flag events lookup
//type for managing buffered out of sequence data
typedef std::map<SequenceNumber32, Ptr<Packet> > UnAckData_t;
class TcpStateMachine {
public:
TcpStateMachine ();
SA Lookup (States_t, Events_t);
Events_t FlagsEvent (uint8_t); // Lookup event from flags
public:
StateActions_t aT; // Action table
EventVec_t eV; // Flags event lookup
};
}//namespace ns3
#endif //TCP_TYPEDEFS_H

View File

@@ -109,7 +109,6 @@ def build(bld):
'arp-cache.cc',
'arp-l3-protocol.cc',
'udp-socket-impl.cc',
'tcp-socket-impl.cc',
'ipv4-end-point-demux.cc',
'udp-socket-factory-impl.cc',
'tcp-socket-factory-impl.cc',
@@ -139,6 +138,13 @@ def build(bld):
'icmpv6-l4-protocol.cc',
'ipv6-test.cc',
'ipv6-extension-header-test-suite.cc',
'tcp-socket-base.cc',
'tcp-rfc793.cc',
'tcp-tahoe.cc',
'tcp-reno.cc',
'tcp-newreno.cc',
'tcp-rx-buffer.cc',
'tcp-tx-buffer.cc',
]
headers = bld.new_task_gen('ns3header')

View File

@@ -176,7 +176,7 @@ SimpleNetDevice::GetMulticast (Ipv4Address multicastGroup) const
Address SimpleNetDevice::GetMulticast (Ipv6Address addr) const
{
return Mac48Address::GetMulticast (addr);
return Mac48Address::GetMulticast (addr);
}
bool

View File

@@ -32,6 +32,8 @@ namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (TcpSocket);
const char* const TcpSocket::TcpStateName[LAST_STATE] = {"CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", "ESTABLISHED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSING", "TIME_WAIT" };
TypeId
TcpSocket::GetTypeId (void)
{
@@ -83,7 +85,7 @@ TcpSocket::GetTypeId (void)
"Timeout value for TCP delayed acks, in seconds",
TimeValue (Seconds (0.2)),
MakeTimeAccessor (&TcpSocket::GetDelAckTimeout,
&TcpSocket::SetDelAckTimeout),
&TcpSocket::SetDelAckTimeout),
MakeTimeChecker ())
.AddAttribute ("DelAckCount",
"Number of packets to wait before sending a TCP ack",
@@ -91,6 +93,12 @@ TcpSocket::GetTypeId (void)
MakeUintegerAccessor (&TcpSocket::GetDelAckMaxCount,
&TcpSocket::SetDelAckMaxCount),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("PersistTimeout",
"Persist timeout to probe for rx window",
TimeValue (Seconds (6)),
MakeTimeAccessor (&TcpSocket::GetPersistTimeout,
&TcpSocket::SetPersistTimeout),
MakeTimeChecker ())
;
return tid;
}

View File

@@ -35,6 +35,21 @@ namespace ns3 {
class Node;
class Packet;
/* Names of the 11 TCP states */
typedef enum {
CLOSED, // 0
LISTEN, // 1
SYN_SENT, // 2
SYN_RCVD, // 3
ESTABLISHED, // 4
CLOSE_WAIT, // 5
LAST_ACK, // 6
FIN_WAIT_1, // 7
FIN_WAIT_2, // 8
CLOSING, // 9
TIME_WAIT, // 10
LAST_STATE } TcpStates_t;
/**
* \ingroup socket
*
@@ -51,6 +66,9 @@ public:
TcpSocket (void);
virtual ~TcpSocket (void);
// Literal names of TCP states for use in log messages */
static const char* const TcpStateName[LAST_STATE];
private:
// Indirect the attribute setting and getting through private virtual methods
virtual void SetSndBufSize (uint32_t size) = 0;
@@ -71,6 +89,8 @@ private:
virtual Time GetDelAckTimeout (void) const = 0;
virtual void SetDelAckMaxCount (uint32_t count) = 0;
virtual uint32_t GetDelAckMaxCount (void) const = 0;
virtual void SetPersistTimeout (Time timeout) = 0;
virtual Time GetPersistTimeout (void) const = 0;
};