From 6c3559792c48c965ebf97daec4bcf4a51d7913ab Mon Sep 17 00:00:00 2001 From: Raj Bhattacharjea Date: Fri, 25 Jan 2008 13:57:38 -0500 Subject: [PATCH] Added in ns-3-tcp (second try) --- examples/tcp-large-transfer-errors.cc | 240 +++++ examples/tcp-large-transfer.cc | 225 ++++ examples/tcp-nonlistening-server.cc | 191 ++++ examples/tcp-small-transfer-oneloss.cc | 222 ++++ examples/tcp-small-transfer.cc | 217 ++++ examples/wscript | 22 + src/applications/packet-sink/packet-sink.cc | 10 + src/applications/packet-sink/packet-sink.h | 1 + src/internet-node/internet-node.cc | 7 + src/internet-node/pending-data.cc | 222 ++++ src/internet-node/pending-data.h | 73 ++ src/internet-node/rtt-estimator.cc | 233 ++++ src/internet-node/rtt-estimator.h | 131 +++ src/internet-node/sequence-number.cc | 66 ++ src/internet-node/sequence-number.h | 67 ++ src/internet-node/tcp-header.cc | 187 ++++ src/internet-node/tcp-header.h | 161 +++ src/internet-node/tcp-impl.cc | 48 + src/internet-node/tcp-impl.h | 58 + src/internet-node/tcp-l4-protocol.cc | 485 +++++++++ src/internet-node/tcp-l4-protocol.h | 111 ++ src/internet-node/tcp-socket.cc | 1077 +++++++++++++++++++ src/internet-node/tcp-socket.h | 161 +++ src/internet-node/tcp-typedefs.h | 111 ++ src/internet-node/wscript | 8 + src/node/socket.cc | 6 + src/node/socket.h | 7 + src/node/tcp.cc | 71 ++ src/node/tcp.h | 67 ++ src/node/wscript | 2 + 30 files changed, 4487 insertions(+) create mode 100644 examples/tcp-large-transfer-errors.cc create mode 100644 examples/tcp-large-transfer.cc create mode 100644 examples/tcp-nonlistening-server.cc create mode 100644 examples/tcp-small-transfer-oneloss.cc create mode 100644 examples/tcp-small-transfer.cc create mode 100644 src/internet-node/pending-data.cc create mode 100644 src/internet-node/pending-data.h create mode 100644 src/internet-node/rtt-estimator.cc create mode 100644 src/internet-node/rtt-estimator.h create mode 100644 src/internet-node/sequence-number.cc create mode 100644 src/internet-node/sequence-number.h create mode 100644 src/internet-node/tcp-header.cc create mode 100644 src/internet-node/tcp-header.h create mode 100644 src/internet-node/tcp-impl.cc create mode 100644 src/internet-node/tcp-impl.h create mode 100644 src/internet-node/tcp-l4-protocol.cc create mode 100644 src/internet-node/tcp-l4-protocol.h create mode 100644 src/internet-node/tcp-socket.cc create mode 100644 src/internet-node/tcp-socket.h create mode 100644 src/internet-node/tcp-typedefs.h create mode 100644 src/node/tcp.cc create mode 100644 src/node/tcp.h diff --git a/examples/tcp-large-transfer-errors.cc b/examples/tcp-large-transfer-errors.cc new file mode 100644 index 000000000..d41a27d74 --- /dev/null +++ b/examples/tcp-large-transfer-errors.cc @@ -0,0 +1,240 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +// +// Network topology +// +// 10Mb/s, 10ms 10Mb/s, 10ms +// n0-----------------n1-----------------n2 +// +// +// - Tracing of queues and packet receptions to file +// "tcp-large-transfer-errors.tr" +// - pcap traces also generated in the following files +// "tcp-large-transfer-errors.pcap-$n-$i" where n and i represent node and interface numbers respectively +// Usage (e.g.): ./waf --run tcp-large-transfer-errors + +#include +#include +#include +#include +#include + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" +#include "ns3/log.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/error-model.h" +#include "ns3/node-list.h" + +#include "ns3/tcp.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpLargeTransferErrors"); + +void +ApplicationTraceSink (const TraceContext &context, Ptr packet, + const Address &addr) +{ + if (!g_log.IsNoneEnabled ()) { + if (InetSocketAddress::IsMatchingType (addr) ) + { + InetSocketAddress address = InetSocketAddress::ConvertFrom (addr); + std::cout << "PacketSink received size " << + packet->GetSize () << " at time " << + Simulator::Now ().GetSeconds () << " from address: " << + address.GetIpv4 () << std::endl; + char buf[2000]; + memcpy(buf, packet->PeekData (), packet->GetSize ()); + for (uint32_t i=0; i < packet->GetSize (); i++) + { + std::cout << buf[i]; + if (i && i % 60 == 0) + std::cout << std::endl; + } + std::cout << std::endl << std::endl; + } + } +} + +void CloseConnection (Ptr localSocket) +{ + //localSocket->Close (); +} + +void StartFlow(Ptr localSocket, uint32_t nBytes, + uint16_t servPort) +{ + // NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ()); + localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort));//connect + localSocket->SetConnectCallback (MakeCallback (&CloseConnection), + Callback > (), + Callback > ()); + //we want to close as soon as the connection is established + //the tcp state machine and outgoing buffer will assure that + //all of the data is delivered + + // Perform series of 1040 byte writes (this is a multiple of 26 since + // we want to detect data splicing in the output stream) + uint32_t writeSize = 1040; + uint8_t data[writeSize]; + while (nBytes > 0) { + uint32_t curSize= nBytes > writeSize ? writeSize : nBytes; + for(uint32_t i = 0; i < curSize; ++i) + { + char m = toascii (97 + i % 26); + data[i] = m; + } + localSocket->Send (data, curSize); + nBytes -= curSize; + } +} + +int main (int argc, char *argv[]) +{ + + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL); +// LogComponentEnable("TcpSocket", LOG_LEVEL_ALL); +// LogComponentEnable("PacketSink", LOG_LEVEL_ALL); + //LogComponentEnable("TcpLargeTransferErrors", LOG_LEVEL_ALL); + + // Allow the user to override any of the defaults and the above + // Bind()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create three nodes. In more sophisticated + // topologies, we could configure a node factory. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n1, DataRate(10000000), MilliSeconds(10)); + + // Later, we add IP addresses. + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address("10.1.3.1"), + n1, Ipv4Address("10.1.3.2")); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate(10000000), MilliSeconds(10)); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address("10.1.2.1"), + n2, Ipv4Address("10.1.2.2")); + + // Finally, we add static routes. These three steps (Channel and + // NetDevice creation, IP Address assignment, and routing) are + // separated because there may be a need to postpone IP Address + // assignment (emulation) or modify to use dynamic routing + PointToPointTopology::AddIpv4Routes(n0, n1, channel0); + PointToPointTopology::AddIpv4Routes(n1, n2, channel1); + Ptr ipv4; + ipv4 = n0->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1); + ipv4 = n2->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1); + + + /////////////////////////////////////////////////////////////////////////// + // Simulation 1 + // + // Send 2000000 bytes over a connection to server port 50000 at time 0 + // Should observe SYN exchange, a lot of data segments, and FIN exchange + // + /////////////////////////////////////////////////////////////////////////// + + int nBytes = 2000000; + uint16_t servPort = 50000; + + Ptr socketFactory = + n0->QueryInterface (Tcp::iid); + Ptr localSocket = socketFactory->CreateSocket (); + localSocket->Bind (); + + // Create a packet sink to receive these packets + Ptr sink = Create ( + n2, + InetSocketAddress (Ipv4Address::GetAny (), servPort), + "Tcp"); + sink->Start (Seconds (0.0)); + sink->Stop (Seconds (10000.0)); + + // + // Error models + // + // We want to add an error model to node 2's NetDevice + // We can obtain a handle to the NetDevice via the channel and node + // pointers + Ptr nd2 = PointToPointTopology::GetNetDevice + (n2, channel1); + Ptr rem = Create (); + // The first data segment for this flow is packet uid=4 + rem->SetRandomVariable (UniformVariable ()); + rem->SetUnit (EU_PKT); + rem->SetRate (0.05); + nd2->AddReceiveErrorModel (rem); + + Simulator::Schedule(Seconds(0), &StartFlow, localSocket, nBytes, + servPort); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-examples.tr file + AsciiTrace asciitrace ("tcp-large-transfer-errors.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named + // simple-examples.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("tcp-large-transfer-errors.pcap"); + pcaptrace.TraceAllIp (); + + NodeList::Connect ("/nodes/*/applications/*/rx", MakeCallback (&ApplicationTraceSink)); + + Simulator::StopAt (Seconds(10000)); + Simulator::Run (); + Simulator::Destroy (); +} diff --git a/examples/tcp-large-transfer.cc b/examples/tcp-large-transfer.cc new file mode 100644 index 000000000..af94d62ec --- /dev/null +++ b/examples/tcp-large-transfer.cc @@ -0,0 +1,225 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +// +// Network topology +// +// 10Mb/s, 10ms 10Mb/s, 10ms +// n0-----------------n1-----------------n2 +// +// +// - Tracing of queues and packet receptions to file +// "tcp-large-transfer.tr" +// - pcap traces also generated in the following files +// "tcp-large-transfer.pcap-$n-$i" where n and i represent node and interface numbers respectively +// Usage (e.g.): ./waf --run tcp-large-transfer + +#include +#include +#include +#include +#include + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" +#include "ns3/log.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/error-model.h" +#include "ns3/node-list.h" + +#include "ns3/tcp.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpLargeTransfer"); + +void +ApplicationTraceSink (const TraceContext &context, Ptr packet, + const Address &addr) +{ + if (!g_log.IsNoneEnabled ()) { + if (InetSocketAddress::IsMatchingType (addr) ) + { + InetSocketAddress address = InetSocketAddress::ConvertFrom (addr); + std::cout << "PacketSink received size " << + packet->GetSize () << " at time " << + Simulator::Now ().GetSeconds () << " from address: " << + address.GetIpv4 () << std::endl; + char buf[2000]; + memcpy(buf, packet->PeekData (), packet->GetSize ()); + for (uint32_t i=0; i < packet->GetSize (); i++) + { + std::cout << buf[i]; + if (i && i % 60 == 0) + std::cout << std::endl; + } + std::cout << std::endl << std::endl; + } + } +} + +void CloseConnection (Ptr localSocket) +{ + //localSocket->Close (); +} + +void StartFlow(Ptr localSocket, uint32_t nBytes, + uint16_t servPort) +{ + // NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ()); + localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort));//connect + localSocket->SetConnectCallback (MakeCallback (&CloseConnection), + Callback > (), + Callback > ()); + //we want to close as soon as the connection is established + //the tcp state machine and outgoing buffer will assure that + //all of the data is delivered + + // Perform series of 1040 byte writes (this is a multiple of 26 since + // we want to detect data splicing in the output stream) + uint32_t writeSize = 1040; + uint8_t data[writeSize]; + while (nBytes > 0) { + uint32_t curSize= nBytes > writeSize ? writeSize : nBytes; + for(uint32_t i = 0; i < curSize; ++i) + { + char m = toascii (97 + i % 26); + data[i] = m; + } + localSocket->Send (data, curSize); + nBytes -= curSize; + } +} + +int main (int argc, char *argv[]) +{ + + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL); +// LogComponentEnable("TcpSocket", LOG_LEVEL_ALL); +// LogComponentEnable("PacketSink", LOG_LEVEL_ALL); + //LogComponentEnable("TcpLargeTransfer", LOG_LEVEL_ALL); + + // Allow the user to override any of the defaults and the above + // Bind()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create three nodes. In more sophisticated + // topologies, we could configure a node factory. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n1, DataRate(10000000), MilliSeconds(10)); + + // Later, we add IP addresses. + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address("10.1.3.1"), + n1, Ipv4Address("10.1.3.2")); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate(10000000), MilliSeconds(10)); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address("10.1.2.1"), + n2, Ipv4Address("10.1.2.2")); + + // Finally, we add static routes. These three steps (Channel and + // NetDevice creation, IP Address assignment, and routing) are + // separated because there may be a need to postpone IP Address + // assignment (emulation) or modify to use dynamic routing + PointToPointTopology::AddIpv4Routes(n0, n1, channel0); + PointToPointTopology::AddIpv4Routes(n1, n2, channel1); + Ptr ipv4; + ipv4 = n0->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1); + ipv4 = n2->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1); + + + /////////////////////////////////////////////////////////////////////////// + // Simulation 1 + // + // Send 2000000 bytes over a connection to server port 50000 at time 0 + // Should observe SYN exchange, a lot of data segments, and FIN exchange + // + /////////////////////////////////////////////////////////////////////////// + + int nBytes = 2000000; + uint16_t servPort = 50000; + + Ptr socketFactory = + n0->QueryInterface (Tcp::iid); + Ptr localSocket = socketFactory->CreateSocket (); + localSocket->Bind (); + + // Create a packet sink to receive these packets + Ptr sink = Create ( + n2, + InetSocketAddress (Ipv4Address::GetAny (), servPort), + "Tcp"); + sink->Start (Seconds (0.0)); + sink->Stop (Seconds (100.0)); + + Simulator::Schedule(Seconds(0), &StartFlow, localSocket, nBytes, + servPort); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-examples.tr file + AsciiTrace asciitrace ("tcp-large-transfer.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named + // simple-examples.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("tcp-large-transfer.pcap"); + pcaptrace.TraceAllIp (); + + NodeList::Connect ("/nodes/*/applications/*/rx", MakeCallback (&ApplicationTraceSink)); + + Simulator::StopAt (Seconds(1000)); + Simulator::Run (); + Simulator::Destroy (); +} diff --git a/examples/tcp-nonlistening-server.cc b/examples/tcp-nonlistening-server.cc new file mode 100644 index 000000000..084328f7e --- /dev/null +++ b/examples/tcp-nonlistening-server.cc @@ -0,0 +1,191 @@ +/* -*- 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 +// +// 100Kb/s, 10ms 1Mb/s, 10ms +// n0-----------------n1-----------------n2 +// +// +// - Tracing of queues and packet receptions to file +// "tcp-nonlistening-server.tr" +// - pcap traces also generated in the following files +// "tcp-nonlistening-server.pcap-$n-$i" where n and i represent node and interface numbers respectively +// Usage (e.g.): ./waf --run tcp-nonlistening-server + +#include +#include +#include +#include + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" +#include "ns3/log.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/error-model.h" + +#include "ns3/tcp.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpNonListeningServer"); + +void ConnectionSucceededCallback (Ptr localSocket) +{ + uint32_t nBytes = 2000; + uint8_t data[nBytes]; + for(uint32_t i = 0; i < nBytes; ++i) + { + char m = 'A'; + data[i] = m; + } //put something interesting in the packets ABCDEF... + localSocket->Send (data, nBytes); +} + +void ConnectionFailedCallback (Ptr localSocket) +{ + NS_LOG_ERROR("Connection failed at time " << Simulator::Now ().GetSeconds ()); +} + +void StartFlow(Ptr localSocket, uint16_t servPort) +{ + NS_LOG_LOGIC(std::endl << "Connection attempt at time " << + Simulator::Now ().GetSeconds () << std::endl); + localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort)); + localSocket->SetConnectCallback ( + MakeCallback (&ConnectionSucceededCallback), + MakeCallback (&ConnectionFailedCallback), + MakeNullCallback > () ); +} + +int main (int argc, char *argv[]) +{ + + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this + //LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL); + //LogComponentEnable("TcpSocket", LOG_LEVEL_ALL); + LogComponentEnable("TcpNonListeningServer", LOG_LEVEL_ALL); + + // Allow the user to override any of the defaults and the above + // Bind()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create three nodes. In more sophisticated + // topologies, we could configure a node factory. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n1, DataRate(1000000), MilliSeconds(10)); + + // Later, we add IP addresses. + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address("10.1.3.1"), + n1, Ipv4Address("10.1.3.2")); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate(100000), MilliSeconds(10)); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address("10.1.2.1"), + n2, Ipv4Address("10.1.2.2")); + + // Finally, we add static routes. These three steps (Channel and + // NetDevice creation, IP Address assignment, and routing) are + // separated because there may be a need to postpone IP Address + // assignment (emulation) or modify to use dynamic routing + PointToPointTopology::AddIpv4Routes(n0, n1, channel0); + PointToPointTopology::AddIpv4Routes(n1, n2, channel1); + Ptr ipv4; + ipv4 = n0->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1); + ipv4 = n2->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1); + + + /////////////////////////////////////////////////////////////////////////// + // Simulation 1 + // + // Send 2000 bytes over a connection to server port 500 at time 0 + // Should observe SYN exchange, two data segments, and FIN exchange + // + /////////////////////////////////////////////////////////////////////////// + + uint16_t servPort = 500; + + Ptr socketFactory = + n0->QueryInterface (Tcp::iid); + Ptr localSocket = socketFactory->CreateSocket (); + localSocket->Bind (); + +#ifdef NOTFORTHISSCRIPT + // Create an optional packet sink to receive these packets + Ptr sink = Create ( + n2, + InetSocketAddress (Ipv4Address::GetAny (), servPort), + "Tcp"); + // Start the sink + sink->Start (Seconds (0.0)); + sink->Stop (Seconds (10.0)); +#endif + + Simulator::Schedule(Seconds(0), &StartFlow, localSocket, servPort); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-examples.tr file + AsciiTrace asciitrace ("tcp-nonlistening-server.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named + // simple-examples.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("tcp-nonlistening-server.pcap"); + pcaptrace.TraceAllIp (); + + + Simulator::StopAt (Seconds(1000)); + Simulator::Run (); + Simulator::Destroy (); +} diff --git a/examples/tcp-small-transfer-oneloss.cc b/examples/tcp-small-transfer-oneloss.cc new file mode 100644 index 000000000..483e81212 --- /dev/null +++ b/examples/tcp-small-transfer-oneloss.cc @@ -0,0 +1,222 @@ +/* -*- 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 +// +// 100Kb/s, 10ms 1Mb/s, 10ms +// n0-----------------n1-----------------n2 +// +// +// - Tracing of queues and packet receptions to file +// "tcp-small-transfer-oneloss.tr" +// - pcap traces also generated in the following files +// "tcp-small-transfer-oneloss.pcap-$n-$i" where n and i represent node and interface numbers respectively +// Usage (e.g.): ./waf --run tcp-small-transfer-oneloss + +#include +#include +#include +#include +#include + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" +#include "ns3/log.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/error-model.h" +#include "ns3/node-list.h" + +#include "ns3/tcp.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpSmallTransferOneloss"); + +void +ApplicationTraceSink (const TraceContext &context, Ptr packet, + const Address &addr) +{ + if (!g_log.IsNoneEnabled ()) { + if (InetSocketAddress::IsMatchingType (addr) ) + { + InetSocketAddress address = InetSocketAddress::ConvertFrom (addr); + std::cout << "PacketSink received size " << + packet->GetSize () << " at time " << + Simulator::Now ().GetSeconds () << " from address: " << + address.GetIpv4 () << std::endl; + char buf[2000]; + memcpy(buf, packet->PeekData (), packet->GetSize ()); + for (uint32_t i=0; i < packet->GetSize (); i++) + { + std::cout << buf[i]; + if (i && i % 60 == 0) + std::cout << std::endl; + } + std::cout << std::endl << std::endl; + } + } +} + +void StartFlow(Ptr localSocket, uint32_t nBytes, + uint16_t servPort) +{ + // NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ()); + localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort)); + uint8_t data[nBytes]; + for(uint32_t i = 0; i < nBytes; ++i) + { + char m = toascii (97 + i % 26); + data[i] = m; + } + localSocket->Send (data, nBytes); +} + +int main (int argc, char *argv[]) +{ + + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL); +// LogComponentEnable("TcpSocket", LOG_LEVEL_ALL); +// LogComponentEnable("PacketSink", LOG_LEVEL_ALL); + LogComponentEnable("TcpSmallTransferOneloss", LOG_LEVEL_ALL); + + // Allow the user to override any of the defaults and the above + // Bind()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create three nodes. In more sophisticated + // topologies, we could configure a node factory. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n1, DataRate(1000000), MilliSeconds(10)); + + // Later, we add IP addresses. + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address("10.1.3.1"), + n1, Ipv4Address("10.1.3.2")); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate(100000), MilliSeconds(10)); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address("10.1.2.1"), + n2, Ipv4Address("10.1.2.2")); + + // Finally, we add static routes. These three steps (Channel and + // NetDevice creation, IP Address assignment, and routing) are + // separated because there may be a need to postpone IP Address + // assignment (emulation) or modify to use dynamic routing + PointToPointTopology::AddIpv4Routes(n0, n1, channel0); + PointToPointTopology::AddIpv4Routes(n1, n2, channel1); + Ptr ipv4; + ipv4 = n0->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1); + ipv4 = n2->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1); + + + /////////////////////////////////////////////////////////////////////////// + // Simulation 1 + // + // Send 2000 bytes over a connection to server port 500 at time 0 + // Should observe SYN exchange, two data segments, and FIN exchange + // Force the loss of the first data segment + // + /////////////////////////////////////////////////////////////////////////// + + int nBytes = 2000; + uint16_t servPort = 500; + + Ptr socketFactory = + n0->QueryInterface (Tcp::iid); + Ptr localSocket = socketFactory->CreateSocket (); + localSocket->Bind (); + + // Create a packet sink to receive these packets + Ptr sink = Create ( + n2, + InetSocketAddress (Ipv4Address::GetAny (), servPort), + "Tcp"); + sink->Start (Seconds (0.0)); + sink->Stop (Seconds (100.0)); + + // + // Error models + // + // We want to add an error model to node 2's NetDevice + // We can obtain a handle to the NetDevice via the channel and node + // pointers + Ptr nd2 = PointToPointTopology::GetNetDevice + (n2, channel1); + Ptr pem = Create (); + std::list sampleList; + // The first data segment for this flow is packet uid=4 + sampleList.push_back (4); + pem->SetList (sampleList); + nd2->AddReceiveErrorModel (pem); + + Simulator::Schedule(Seconds(0), &StartFlow, localSocket, nBytes, + servPort); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-examples.tr file + AsciiTrace asciitrace ("tcp-small-transfer-oneloss.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named + // simple-examples.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("tcp-small-transfer-oneloss.pcap"); + pcaptrace.TraceAllIp (); + + NodeList::Connect ("/nodes/*/applications/*/rx", MakeCallback (&ApplicationTraceSink)); + + Simulator::StopAt (Seconds(1000)); + Simulator::Run (); + Simulator::Destroy (); +} diff --git a/examples/tcp-small-transfer.cc b/examples/tcp-small-transfer.cc new file mode 100644 index 000000000..4b96cd467 --- /dev/null +++ b/examples/tcp-small-transfer.cc @@ -0,0 +1,217 @@ +/* -*- 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 +// +// 100Kb/s, 10ms 1Mb/s, 10ms +// n0-----------------n1-----------------n2 +// +// +// - Tracing of queues and packet receptions to file +// "tcp-small-transfer.tr" +// - pcap traces also generated in the following files +// "tcp-small-transfer.pcap-$n-$i" where n and i represent node and interface numbers respectively +// Usage (e.g.): ./waf --run tcp-small-transfer + +#include +#include +#include +#include +#include + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" +#include "ns3/log.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/error-model.h" +#include "ns3/node-list.h" + +#include "ns3/tcp.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpSmallTransfer"); + +void +ApplicationTraceSink (const TraceContext &context, Ptr packet, + const Address &addr) +{ + if (!g_log.IsNoneEnabled ()) { + if (InetSocketAddress::IsMatchingType (addr) ) + { + InetSocketAddress address = InetSocketAddress::ConvertFrom (addr); + std::cout << "PacketSink received size " << + packet->GetSize () << " at time " << + Simulator::Now ().GetSeconds () << " from address: " << + address.GetIpv4 () << std::endl; + char buf[2000]; + memcpy(buf, packet->PeekData (), packet->GetSize ()); + for (uint32_t i=0; i < packet->GetSize (); i++) + { + std::cout << buf[i]; + if (i && i % 60 == 0) + std::cout << std::endl; + } + std::cout << std::endl << std::endl; + } + } +} + +void CloseConnection (Ptr localSocket) +{ + localSocket->Close (); +} + +void StartFlow(Ptr localSocket, uint32_t nBytes, + uint16_t servPort) +{ + // NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ()); + localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort));//connect + localSocket->SetConnectCallback (MakeCallback (&CloseConnection), + MakeNullCallback > (), + MakeNullCallback > ()); + //we want to close as soon as the connection is established + //the tcp state machine and outgoing buffer will assure that + //all of the data is delivered + uint8_t data[nBytes]; + for(uint32_t i = 0; i < nBytes; ++i) + { + char m = toascii (97 + i % 26); + data[i] = m; + } + localSocket->Send (data, nBytes); +} + +int main (int argc, char *argv[]) +{ + + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL); + // LogComponentEnable("TcpSocket", LOG_LEVEL_ALL); +// LogComponentEnable("PacketSink", LOG_LEVEL_ALL); + LogComponentEnable("TcpSmallTransfer", LOG_LEVEL_ALL); + + // Allow the user to override any of the defaults and the above + // Bind()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create three nodes. In more sophisticated + // topologies, we could configure a node factory. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n1, DataRate(1000000), MilliSeconds(10)); + + // Later, we add IP addresses. + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address("10.1.3.1"), + n1, Ipv4Address("10.1.3.2")); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate(100000), MilliSeconds(10)); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address("10.1.2.1"), + n2, Ipv4Address("10.1.2.2")); + + // Finally, we add static routes. These three steps (Channel and + // NetDevice creation, IP Address assignment, and routing) are + // separated because there may be a need to postpone IP Address + // assignment (emulation) or modify to use dynamic routing + PointToPointTopology::AddIpv4Routes(n0, n1, channel0); + PointToPointTopology::AddIpv4Routes(n1, n2, channel1); + Ptr ipv4; + ipv4 = n0->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1); + ipv4 = n2->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1); + + + /////////////////////////////////////////////////////////////////////////// + // Simulation 1 + // + // Send 2000 bytes over a connection to server port 500 at time 0 + // Should observe SYN exchange, two data segments, and FIN exchange + // + /////////////////////////////////////////////////////////////////////////// + + int nBytes = 2000; + uint16_t servPort = 500; + + Ptr socketFactory = + n0->QueryInterface (Tcp::iid); + Ptr localSocket = socketFactory->CreateSocket (); + localSocket->Bind (); + + // Create a packet sink to receive these packets + Ptr sink = Create ( + n2, + InetSocketAddress (Ipv4Address::GetAny (), servPort), + "Tcp"); + sink->Start (Seconds (0.0)); + sink->Stop (Seconds (100.0)); + + Simulator::Schedule(Seconds(0), &StartFlow, localSocket, nBytes, + servPort); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-examples.tr file + AsciiTrace asciitrace ("tcp-small-transfer.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named + // simple-examples.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("tcp-small-transfer.pcap"); + pcaptrace.TraceAllIp (); + + NodeList::Connect ("/nodes/*/applications/*/rx", MakeCallback (&ApplicationTraceSink)); + + Simulator::StopAt (Seconds(1000)); + Simulator::Run (); + Simulator::Destroy (); +} diff --git a/examples/wscript b/examples/wscript index e458fa057..2074067fc 100644 --- a/examples/wscript +++ b/examples/wscript @@ -45,3 +45,25 @@ def build(bld): obj = bld.create_ns3_program('simple-point-to-point-olsr', ['point-to-point', 'internet-node', 'olsr']) obj.source = 'simple-point-to-point-olsr.cc' + + obj = bld.create_ns3_program('tcp-large-transfer', + ['point-to-point', 'internet-node']) + obj.source = 'tcp-large-transfer.cc' + + obj = bld.create_ns3_program('tcp-large-transfer-errors', + ['point-to-point', 'internet-node']) + obj.source = 'tcp-large-transfer-errors.cc' + + obj = bld.create_ns3_program('tcp-nonlistening-server', + ['point-to-point', 'internet-node']) + obj.source = 'tcp-nonlistening-server.cc' + + obj = bld.create_ns3_program('tcp-small-transfer', + ['point-to-point', 'internet-node']) + obj.source = 'tcp-small-transfer.cc' + + obj = bld.create_ns3_program('tcp-small-transfer-oneloss', + ['point-to-point', 'internet-node']) + obj.source = 'tcp-small-transfer-oneloss.cc' + + diff --git a/src/applications/packet-sink/packet-sink.cc b/src/applications/packet-sink/packet-sink.cc index 12a5515b9..e9f49e017 100644 --- a/src/applications/packet-sink/packet-sink.cc +++ b/src/applications/packet-sink/packet-sink.cc @@ -78,9 +78,14 @@ void PacketSink::StartApplication() // Called at time specified by Start GetNode ()->QueryInterface (iid); m_socket = socketFactory->CreateSocket (); m_socket->Bind (m_local); + m_socket->Listen (0); } m_socket->SetRecvCallback (MakeCallback(&PacketSink::Receive, this)); + m_socket->SetAcceptCallback ( + MakeNullCallback, const Address &> (), + MakeNullCallback, const Address&> (), + MakeCallback(&PacketSink::CloseConnection, this) ); } void PacketSink::StopApplication() // Called at time specified by Stop @@ -106,6 +111,11 @@ void PacketSink::Receive(Ptr socket, Ptr packet, m_rxTrace (packet, from); } +void PacketSink::CloseConnection (Ptr socket) +{ + socket->Close (); +} + Ptr PacketSink::GetTraceResolver (void) const { diff --git a/src/applications/packet-sink/packet-sink.h b/src/applications/packet-sink/packet-sink.h index 96fc7f98f..7ad8d88fe 100644 --- a/src/applications/packet-sink/packet-sink.h +++ b/src/applications/packet-sink/packet-sink.h @@ -78,6 +78,7 @@ private: std::string iid); virtual void Receive (Ptr socket, Ptr packet, const Address& from); + virtual void CloseConnection (Ptr socket); Ptr m_socket; // Associated socket Address m_local; // Local address to bind to diff --git a/src/internet-node/internet-node.cc b/src/internet-node/internet-node.cc index 5a927b55f..f46df4edd 100644 --- a/src/internet-node/internet-node.cc +++ b/src/internet-node/internet-node.cc @@ -28,9 +28,11 @@ #include "ipv4-l4-demux.h" #include "internet-node.h" #include "udp-l4-protocol.h" +#include "tcp-l4-protocol.h" #include "ipv4-l3-protocol.h" #include "arp-l3-protocol.h" #include "udp-impl.h" +#include "tcp-impl.h" #include "ipv4-impl.h" namespace ns3 { @@ -62,15 +64,20 @@ InternetNode::Construct (void) Ptr ipv4L4Demux = Create (this); Ptr udp = Create (this); + Ptr tcp = Create (this); + ipv4L4Demux->Insert (udp); + ipv4L4Demux->Insert (tcp); Ptr udpImpl = Create (udp); + Ptr tcpImpl = Create (tcp); Ptr ipv4Impl = Create (ipv4); Object::AddInterface (ipv4); Object::AddInterface (arp); Object::AddInterface (ipv4Impl); Object::AddInterface (udpImpl); + Object::AddInterface (tcpImpl); Object::AddInterface (ipv4L4Demux); } diff --git a/src/internet-node/pending-data.cc b/src/internet-node/pending-data.cc new file mode 100644 index 000000000..3fa9207a7 --- /dev/null +++ b/src/internet-node/pending-data.cc @@ -0,0 +1,222 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// All rights reserved. +// +// 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: Rajib Bhattacharjea +// + + +// This is a port of Data PDU Headers from: +// Georgia Tech Network Simulator +// George F. Riley. Georgia Tech, Spring 2002 + +#include +#include + +#include + +#include "pending-data.h" +#include "ns3/packet.h" +#include "ns3/fatal-error.h" +namespace ns3 +{ + +namespace Serializable +{ + uint8_t* GetSize (uint8_t* b, uint32_t& r, uint32_t& s) + { // Get the size of the next size field + if (sizeof(s) > r) + { + NS_FATAL_ERROR ("Serialization error; remaining " << r + << " thissize " << sizeof(s) << std::endl); + } + r -= sizeof (s); // Reduce remaining for next time + memcpy (&s, b, sizeof(s)); + return b + sizeof (s); + } +} + +PendingData::PendingData () : size (0), data (0), + msgSize (0), responseSize (0) +{ +} + +PendingData::PendingData (uint32_t s, uint8_t* d, uint32_t msg, uint32_t resp) + : size (s), data (0), msgSize (msg), responseSize (resp) +{ // Make a copy of the data + if (d) + { + data = new uint8_t[s]; + memcpy (data, d, s); + } +} + +PendingData::PendingData(const std::string& s) + : size (s.length () + 1), data ((uint8_t*)strdup(s.c_str ())), + msgSize (0), responseSize (0) +{ +} + +PendingData::PendingData(const PendingData& c) + : size (c.Size ()), data (0), + msgSize (c.msgSize), responseSize (c.responseSize) +{ // Copy constructor + if (c.Contents()) + { // Has data + data = new uint8_t[Size ()]; + memcpy(data, c.Contents (), Size ()); + } +} + +PendingData::~PendingData() +{ // destructor + if (data) + { + delete [] data; + } +} + +PendingData* PendingData::Copy () const +{ + return new PendingData (*this); +}; + +PendingData* PendingData::CopyS (uint32_t s) +{ // Copy, but with new size (assumes no associated data); + return new PendingData (s, 0, msgSize, responseSize); +} + +PendingData* PendingData::CopySD (uint32_t s, uint8_t* d) +{ // Copy, but with new size (assumes no associated data); + return new PendingData (s, d, msgSize, responseSize); +} + +void PendingData::Clear () +{ // Remove all pending data + if (data) + { + delete [] data; // Free memory if used + } + data = 0; + size = 0; +} + +void PendingData::Add (uint32_t s, const uint8_t* d) +{ + if (data) + { // PendingData exists, realloc and copy + uint8_t* n = new uint8_t[Size () + s]; + memcpy(n, data, Size ()); + if (d) + { // New data specified + memcpy(n + Size (), d, s); // Append the new data + } + else + { + memset(n + Size (), 0, s); // Apend zeros + } + delete [] data; // Delete the old data + data = n; // Points to new one + } + else + { // No existing data, see if new data + if (d) + { + data = new uint8_t[s]; + memcpy (data, d, s); + } + } + size += s; +} + +void PendingData::Remove(uint32_t s) +{ + uint32_t r = s > Size () ? Size () : s; + + size -= r; // Reduce size from current + if (data) + { // data actually exists, realloc and copy + if (size) + { + uint8_t* d = new uint8_t[Size ()]; + memcpy(d, data, Size ()); + delete [] data; + data = d; + } + else + { // Zero size, so don't need the data anymore + delete [] data; + data = NULL; + } + } +} + +uint32_t PendingData::SizeFromSeq (const SequenceNumber& f, const SequenceNumber& o) +{ + uint32_t o1 = OffsetFromSeq (f,o); // Offset to start of unused data + return SizeFromOffset (o1); // Amount of data after offset +} + +uint32_t PendingData::SizeFromOffset (uint32_t o) +{ // Find out how much data is available from offset + if (o > size) return 0; // No data at requested offset + return size - o; // Available data after offset +} + +uint32_t PendingData::OffsetFromSeq (const SequenceNumber& f, const SequenceNumber& o) +{ // f is the first sequence number in this data, o is offset sequence + if (o < f) + { + return 0; // HuH? Shouldn't happen + } + return o - f; +} + +PendingData* PendingData::CopyFromOffset (uint32_t s, uint32_t o) +{ // Make a copy of data from starting position "o" for "s" bytes + // Return NULL if results in zero length data + uint32_t s1 = std::min (s, SizeFromOffset (o)); // Insure not beyond end of data + if (s1 == 0) + { + return NULL; // No data requested + } + if (data) + { // Actual data exists, make copy and return it + uint8_t* d1 = new uint8_t[s1]; // Allocate memory for the copy + memcpy (d1, &data[o], s1); // Copy the data + PendingData* d = new PendingData (s1, d1, msgSize, responseSize); // Return copy + return d; + } + else + { // No actual data, just return non-data pdu of correct size + return new PendingData (s1, 0, msgSize, responseSize); + } +} + +PendingData* PendingData::CopyFromSeq (uint32_t s, const SequenceNumber& f, const SequenceNumber& o) +{ + PendingData* d = CopyFromOffset (s, OffsetFromSeq(f,o)); + return d; +} + +}//namepsace ns3 + + + + + + diff --git a/src/internet-node/pending-data.h b/src/internet-node/pending-data.h new file mode 100644 index 000000000..137faa2d4 --- /dev/null +++ b/src/internet-node/pending-data.h @@ -0,0 +1,73 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// All rights reserved. +// +// 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: Rajib Bhattacharjea +// + +// Georgia Tech Network Simulator - Data Descriptors +// George F. Riley. Georgia Tech, Spring 2002 + +#ifndef __datapdu_h__ +#define __datapdu_h__ + +#include "pending-data.h" +#include "sequence-number.h" +namespace ns3 +{ +class Packet; +//Doc:ClassXRef +class PendingData { +public: + PendingData (); + PendingData (uint32_t s, uint8_t* d = NULL, uint32_t msg = 0, uint32_t resp = 0); + PendingData (const std::string&); // Construct from string + PendingData (uint8_t*, uint32_t&, Packet*); // Construct from serialized buffer + PendingData (const PendingData&); // Copy constructor + virtual ~PendingData (); // Destructor + uint32_t Size () const { return size;} + // Serialization + uint32_t SSize (); // Size needed for serialization + uint8_t* Serialize (uint8_t*, uint32_t&); // Serialize to a buffer + uint8_t* Construct (uint8_t*, uint32_t&); // Construct from buffer + virtual void Clear ();// Remove all associated data + virtual void Add (uint32_t s, const uint8_t* d = 0);// Add some data to end + virtual void Remove (uint32_t); // Remove data from head + // Inquire available data from (f,o) sequence pair + virtual uint32_t SizeFromSeq (const SequenceNumber&, const SequenceNumber&); + // Inquire available data from offset + virtual uint32_t SizeFromOffset (uint32_t); + // Available size from sequence difference + virtual uint32_t OffsetFromSeq (const SequenceNumber&, const SequenceNumber&); + virtual PendingData* CopyFromOffset (uint32_t, uint32_t); // Size, offset, ret pointer + // Copy data, size, offset specified by sequence difference + virtual PendingData* CopyFromSeq (uint32_t, const SequenceNumber&, const SequenceNumber&); + PendingData* Copy () const; // Create a copy of this header + PendingData* CopyS (uint32_t); // Copy with new size + PendingData* CopySD (uint32_t, uint8_t*); // Copy with new size, new data + virtual uint8_t* Contents() const { return data;} +public: + uint32_t size; // Number of data bytes + uint8_t* data; // Corresponding data (may be null) + // The next two fields allow simulated applications to exchange some info + uint32_t msgSize; // Total size of message + uint32_t responseSize;// Size of response requested +}; + +}//namepsace ns3 +#endif + diff --git a/src/internet-node/rtt-estimator.cc b/src/internet-node/rtt-estimator.cc new file mode 100644 index 000000000..eb202758a --- /dev/null +++ b/src/internet-node/rtt-estimator.cc @@ -0,0 +1,233 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 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: Rajib Bhattacharjea +// + + +// Ported from: +// Georgia Tech Network Simulator - Round Trip Time Estimation Class +// George F. Riley. Georgia Tech, Spring 2002 + +// Implements several variations of round trip time estimators + +#include + +#include "rtt-estimator.h" +#include "ns3/simulator.h" + +namespace ns3{ + +//RttEstimator iid +const InterfaceId RttEstimator::iid = MakeInterfaceId ("RttEstimator", + Object::iid); + +//Default values +ClassIdDefaultValue RttEstimator::defaultCid ("RttEstimator", + "Tahoe round trip time estimation", + RttEstimator::iid, "RttMeanDeviation"); +NumericDefaultValue RttEstimator::defaultMaxMultiplier ("RttMaxMultiplier","",64.0); + +// RttEstimator Static Member variables +Time RttEstimator::initialEstimate = Seconds (1.0); // Default initial estimate + +//RttHistory methods +RttHistory::RttHistory (SequenceNumber s, uint32_t c, Time t) + : seq (s), count (c), time (t), retx (false) + { + } + +RttHistory::RttHistory (const RttHistory& h) + : seq (h.seq), count (h.count), time (h.time), retx (h.retx) + { + } + +// Base class methods + +RttEstimator::RttEstimator () : next (1), history (), est (initialEstimate), + nSamples (0), multiplier (1.0) +{ + //note next=1 everywhere since first segment will have sequence 1 + SetInterfaceId (RttEstimator::iid); +} + +RttEstimator::RttEstimator (Time e) : next (1), history (), est (e), + nSamples (0), multiplier (1.0) +{ + SetInterfaceId (RttEstimator::iid); +} + +RttEstimator::RttEstimator(const RttEstimator& c) + : next(c.next), history(c.history), est(c.est), nSamples(c.nSamples), + multiplier(c.multiplier) +{ + SetInterfaceId (RttEstimator::iid); +} + +RttEstimator::~RttEstimator () +{ +} + +void RttEstimator::SentSeq (SequenceNumber s, uint32_t c) +{ // Note that a particular sequence has been sent + if (s == next) + { // This is the next expected one, just log at end + history.push_back (RttHistory (s, c, Simulator::Now () )); + next = s + SequenceNumber (c); // Update next expected + } + else + { // This is a retransmit, find in list and mark as re-tx + for (RttHistory_t::iterator i = history.begin (); i != history.end (); ++i) + { + if ((s >= i->seq) && (s < (i->seq + SequenceNumber (i->count)))) + { // Found it + i->retx = true; + // One final test..be sure this re-tx does not extend "next" + if ((s + SequenceNumber (c)) > next) + { + next = s + SequenceNumber (c); + i->count = ((s + SequenceNumber (c)) - i->seq); // And update count in hist + } + break; + } + } + } +} + +Time RttEstimator::AckSeq (SequenceNumber a) +{ // An ack has been received, calculate rtt and log this measurement + // Note we use a linear search (O(n)) for this since for the common + // case the ack'ed packet will be at the head of the list + Time m = Seconds (0.0); + if (history.size () == 0) return (m); // No pending history, just exit + RttHistory& h = history.front (); + if (!h.retx && a >= (h.seq + SequenceNumber (h.count))) + { // Ok to use this sample + m = Simulator::Now () - h.time; // Elapsed time + Measurement(m); // Log the measurement + ResetMultiplier(); // Reset multiplier on valid measurement + } + // Now delete all ack history with seq <= ack + while(history.size() > 0) + { + RttHistory& h = history.front (); + if ((h.seq + SequenceNumber(h.count)) > a) break; // Done removing + history.pop_front (); // Remove + } + return m; +} + +void RttEstimator::ClearSent () +{ // Clear all history entries + next = 1; + history.clear (); +} + +void RttEstimator::IncreaseMultiplier () +{ + multiplier = std::min (multiplier * 2.0, defaultMaxMultiplier.GetValue ()); +} + +void RttEstimator::ResetMultiplier () +{ + multiplier = 1.0; +} + +void RttEstimator::Reset () +{ // Reset to initial state + next = 1; + est = initialEstimate; + history.clear (); // Remove all info from the history + nSamples = 0; + ResetMultiplier (); +} + +// Base class, static methods +void RttEstimator::InitialEstimate (Time e) +{ // Set a new default initial estimate + initialEstimate = e; +} + +Ptr RttEstimator::CreateDefault () +{ + ClassId classId = defaultCid.GetValue (); + Ptr rtte = ComponentManager::Create ( + classId, RttEstimator::iid, 0.1, initialEstimate + ); + return rtte; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Mean-Deviation Estimator +const ClassId RttMeanDeviation::cid = + MakeClassId ("RttMeanDeviation", + RttEstimator::iid); + +RttMeanDeviation::RttMeanDeviation(double g) : + gain (g), variance (ns3::Seconds(0)) +{ +} + +RttMeanDeviation::RttMeanDeviation (const RttMeanDeviation& c) + : RttEstimator (c), gain (c.gain), variance (c.variance) +{ +} + +RttMeanDeviation::RttMeanDeviation (double g, Time e) : + RttEstimator (e), gain (g), variance (ns3::Seconds(0)) +{ +} + +void RttMeanDeviation::Measurement (Time m) +{ + if (nSamples) + { // Not first + Time err = m - est; + est = est + Scalar (gain) * err; // estimated rtt + err = Abs (err); // absolute value of error + variance = variance + Scalar (gain) * (err - variance); // variance of rtt + } + else + { // First sample + est = m; // Set estimate to current + //variance = m / 2; // And variance to current / 2 + variance = m; // try this + } + nSamples++; +} + +Time RttMeanDeviation::RetransmitTimeout () +{ + // If not enough samples, justjust return 2 times estimate + //if (nSamples < 2) return est * 2; + if (variance < est / Scalar (4.0)) + return est * Scalar (2 * multiplier); // At least twice current est + return (est + Scalar (4) * variance) * Scalar (multiplier); // As suggested by Jacobson +} + +RttEstimator* RttMeanDeviation::Copy () const +{ + return new RttMeanDeviation (*this); +} + +void RttMeanDeviation::Reset () +{ // Reset to initial state + variance = Seconds (0.0); + RttEstimator::Reset (); +} +}//namepsace ns3 diff --git a/src/internet-node/rtt-estimator.h b/src/internet-node/rtt-estimator.h new file mode 100644 index 000000000..43f443592 --- /dev/null +++ b/src/internet-node/rtt-estimator.h @@ -0,0 +1,131 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 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: Rajib Bhattacharjea +// + +// Georgia Tech Network Simulator - Round Trip Time Estimation Class +// George F. Riley. Georgia Tech, Spring 2002 + +// Implements several variations of round trip time estimators + +#ifndef __rtt_estimator_h__ +#define __rtt_estimator_h__ + +#include +#include "sequence-number.h" +#include "ns3/nstime.h" +#include "ns3/object.h" +#include "ns3/component-manager.h" + +namespace ns3 { + +class RttHistory { +public: + RttHistory (SequenceNumber s, uint32_t c, Time t); + RttHistory (const RttHistory& h); // Copy constructor +public: + SequenceNumber seq; // First sequence number in packet sent + uint32_t count; // Number of bytes sent + Time time; // Time this one was sent + bool retx; // True if this has been retransmitted +}; + +typedef std::deque RttHistory_t; + +class RttEstimator : public Object { // Base class for all RTT Estimators +public: + static const InterfaceId iid; + + RttEstimator(); + RttEstimator(Time e); + RttEstimator(const RttEstimator&); // Copy constructor + virtual ~RttEstimator(); + + virtual void SentSeq(SequenceNumber, uint32_t); + virtual Time AckSeq(SequenceNumber); + virtual void ClearSent(); + virtual void Measurement(Time t) = 0; + virtual Time Estimate() = 0; + virtual Time RetransmitTimeout() = 0; + void Init(SequenceNumber s) { next = s;} + virtual RttEstimator* Copy() const = 0; + virtual void IncreaseMultiplier(); + virtual void ResetMultiplier(); + virtual void Reset(); + +private: + SequenceNumber next; // Next expected sequence to be sent + RttHistory_t history; // List of sent packet +public: + Time est; // Current estimate + uint32_t nSamples;// Number of samples + double multiplier; // RTO Multiplier +public: + static void InitialEstimate(Time); + static Ptr CreateDefault(); // Retrieve current default + + static ClassIdDefaultValue defaultCid; + static NumericDefaultValue defaultMaxMultiplier; + +private: + static Time initialEstimate; // Default initial estimate +}; + +// The "Mean-Deviation" estimator, as discussed by Van Jacobson +// "Congestion Avoidance and Control", SIGCOMM 88, Appendix A + + //Doc:Class Class {\tt RttMeanDeviation} implements the "Mean--Deviation" estimator + //Doc:Class as described by Van Jacobson + //Doc:Class "Congestion Avoidance and Control", SIGCOMM 88, Appendix A +class RttMeanDeviation : public RttEstimator { +public : + static const ClassId cid; + + //Doc:Desc Constructor for {\tt RttMeanDeviation} specifying the gain factor for the + //Doc:Desc estimator. + //Doc:Arg1 Gain factor. + RttMeanDeviation (double g); + + //Doc:Desc Constructor for {\tt RttMeanDeviation} specifying the gain factor + //Doc:Desc and the initial estimate. + //Doc:Arg1 Gain factor. + //Doc:Arg2 Initial estimate. + RttMeanDeviation (double g, Time e); + + //Doc:Method + RttMeanDeviation (const RttMeanDeviation&); // Copy constructor + //Doc:Desc Copy constructor. + //Doc:Arg1 {\tt RttMeanDeviation} object to copy. + + void Measurement (Time); + Time Estimate () { return est;} + Time Variance () { return variance;} + Time RetransmitTimeout (); + RttEstimator* Copy () const; + void Reset (); + void Gain (double g) { gain = g;} + +public: + double gain; // Filter gain + Time variance; // Current variance +}; +}//namespace ns3 +#endif + + + diff --git a/src/internet-node/sequence-number.cc b/src/internet-node/sequence-number.cc new file mode 100644 index 000000000..9d24e4dd0 --- /dev/null +++ b/src/internet-node/sequence-number.cc @@ -0,0 +1,66 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// All rights reserved. +// +// 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: Rajib Bhattacharjea +// + + +// Ported from: +// Georgia Tech Network Simulator - Manage 32 bit unsigned sequence numbers +// George F. Riley. Georgia Tech, Spring 2002 + +// Class to manage arithmetic operations on sequence numbers (mod 2^32) + +#include "sequence-number.h" + +bool operator< (const SequenceNumber l, const SequenceNumber r) +{ // Account for 32 bit rollover + if (l.seq > 0xc0000000 && r.seq < 0x40000000) return true; // Rollover + return l.seq < r.seq; +} + +bool operator<= (const SequenceNumber l, const SequenceNumber r) +{ // Account for 32 bit rollover + if (l.seq > 0xc0000000 && r.seq < 0x40000000) return true; // Rollover + return l.seq <= r.seq; +} + +bool operator> (const SequenceNumber l, const SequenceNumber r) +{ // Account for 32 bit rollover + if (l.seq > 0xc0000000 && r.seq < 0x40000000) return false; // Rollover + return l.seq > r.seq; +} + +bool operator>= (const SequenceNumber l, const SequenceNumber r) +{ // Account for 32 bit rollover + if (l.seq > 0xc0000000 && r.seq < 0x40000000) return false; // Rollover + return l.seq >= r.seq; +} + +// Non-Member Arithmetic operators +SequenceNumber operator+ (const SequenceNumber l, const SequenceNumber r) +{ + return SequenceNumber (l.seq + r.seq); +} + +SequenceNumber operator- (const SequenceNumber l, const SequenceNumber r) +{ // This assumes l is always bigger than r (allows for rollover) + if (l.seq >= r.seq) return SequenceNumber (l.seq-r.seq); + return SequenceNumber ((MAX_SEQ - r.seq) + l.seq + 1); // Adjust for rollover +} + diff --git a/src/internet-node/sequence-number.h b/src/internet-node/sequence-number.h new file mode 100644 index 000000000..81f635816 --- /dev/null +++ b/src/internet-node/sequence-number.h @@ -0,0 +1,67 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// All rights reserved. +// +// 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: Rajib Bhattacharjea +// + +// Ported from: +// Georgia Tech Network Simulator - Manage 32 bit unsigned sequence numbers +// George F. Riley. Georgia Tech, Spring 2002 + +// Class to manage arithmetic operations on sequence numbers (mod 2^32) + +#ifndef __seq_h__ +#define __seq_h__ + +#include + +#define MAX_SEQ ((uint32_t)0xffffffff) + +class SequenceNumber { +public: + SequenceNumber () : seq(0) { } + SequenceNumber (const uint32_t s) : seq (s) { } + + operator uint32_t () const { return seq;} + + SequenceNumber& operator= (const uint32_t s) { seq = s; return *this;} + + SequenceNumber& operator+= (const uint32_t s) { seq += s; return *this;} + SequenceNumber operator++ () { seq++; return *this;} + SequenceNumber operator++ (int) { SequenceNumber ss (seq); seq++; return ss;} + SequenceNumber& operator-= (const uint32_t s) { seq -= s; return *this;} + SequenceNumber operator-- () { seq--; return *this;} + SequenceNumber operator-- (int) { SequenceNumber ss (seq); seq--; return ss;} +public: + uint32_t seq; +}; + +// Comparison operators + +bool operator< (const SequenceNumber l, const SequenceNumber r); +bool operator<= (const SequenceNumber l, const SequenceNumber r); +bool operator> (const SequenceNumber l, const SequenceNumber r); +bool operator>= (const SequenceNumber l, const SequenceNumber r); + +// Non-member arithmetic operators +SequenceNumber operator+ (const SequenceNumber l, const SequenceNumber r); +SequenceNumber operator- (const SequenceNumber l, const SequenceNumber r); + +#endif + + diff --git a/src/internet-node/tcp-header.cc b/src/internet-node/tcp-header.cc new file mode 100644 index 000000000..15905d71e --- /dev/null +++ b/src/internet-node/tcp-header.cc @@ -0,0 +1,187 @@ +/* -*- 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 + */ + +#include +#include +#include "tcp-socket.h" +#include "tcp-header.h" +#include "ns3/buffer.h" + +namespace ns3 { + +NS_HEADER_ENSURE_REGISTERED (TcpHeader); + +bool TcpHeader::m_calcChecksum = false; + +uint32_t +TcpHeader::GetUid (void) +{ + static uint32_t uid = AllocateUid ("TcpHeader.ns3"); + return uid; +} + +TcpHeader::TcpHeader () + : m_sourcePort (0), + m_destinationPort (0), + m_sequenceNumber (0), + m_ackNumber (0), + m_length (5), + m_flags (0), + m_windowSize (Tcp::defaultAdvWin.GetValue ()), + m_checksum (0), + m_urgentPointer (0) +{ +} + +TcpHeader::~TcpHeader () +{} + +void +TcpHeader::EnableChecksums (void) +{ + m_calcChecksum = true; +} + +void TcpHeader::SetSourcePort (uint16_t port) +{ + m_sourcePort = port; +} +void TcpHeader::SetDestinationPort (uint16_t port) +{ + m_destinationPort = port; +} +void TcpHeader::SetSequenceNumber (SequenceNumber sequenceNumber) +{ + m_sequenceNumber = sequenceNumber; +} +void TcpHeader::SetAckNumber (SequenceNumber ackNumber) +{ + m_ackNumber = ackNumber; +} +void TcpHeader::SetLength (uint8_t length) +{ + m_length = length; +} +void TcpHeader::SetFlags (uint8_t flags) +{ + m_flags = flags; +} +void TcpHeader::SetWindowSize (uint16_t windowSize) +{ + m_windowSize = windowSize; +} +void TcpHeader::SetChecksum (uint16_t checksum) +{ + m_checksum = checksum; +} +void TcpHeader::SetUrgentPointer (uint16_t urgentPointer) +{ + m_urgentPointer = urgentPointer; +} + +uint16_t TcpHeader::GetSourcePort () const +{ + return m_sourcePort; +} +uint16_t TcpHeader::GetDestinationPort () const +{ + return m_destinationPort; +} +SequenceNumber TcpHeader::GetSequenceNumber () const +{ + return m_sequenceNumber; +} +SequenceNumber TcpHeader::GetAckNumber () const +{ + return m_ackNumber; +} +uint8_t TcpHeader::GetLength () const +{ + return m_length; +} +uint8_t TcpHeader::GetFlags () const +{ + return m_flags; +} +uint16_t TcpHeader::GetWindowSize () const +{ + return m_windowSize; +} +uint16_t TcpHeader::GetChecksum () const +{ + return m_checksum; +} +uint16_t TcpHeader::GetUrgentPointer () const +{ + return m_urgentPointer; +} + +void +TcpHeader::InitializeChecksum (Ipv4Address source, + Ipv4Address destination, + uint8_t protocol) +{ + m_checksum = 0; +//XXX requires peeking into IP to get length of the TCP segment +} + +std::string +TcpHeader::GetName (void) const +{ + return "TCP"; +} + +void TcpHeader::Print (std::ostream &os) const +{ + //XXX +} +uint32_t TcpHeader::GetSerializedSize (void) const +{ + return 20; //tcp headers are 20 bytes +} +void TcpHeader::Serialize (Buffer::Iterator start) const +{ + start.WriteHtonU16 (m_sourcePort); + start.WriteHtonU16 (m_destinationPort); + start.WriteHtonU32 (m_sequenceNumber); + start.WriteHtonU32 (m_ackNumber); + start.WriteHtonU16 (m_length << 12 | m_flags); //reserved bits are all zero + start.WriteHtonU16 (m_windowSize); + //XXX calculate checksum here + start.WriteHtonU16 (m_checksum); + start.WriteHtonU16 (m_urgentPointer); +} +uint32_t TcpHeader::Deserialize (Buffer::Iterator start) +{ + m_sourcePort = start.ReadNtohU16 (); + m_destinationPort = start.ReadNtohU16 (); + m_sequenceNumber = start.ReadNtohU32 (); + m_ackNumber = start.ReadNtohU32 (); + uint16_t field = start.ReadNtohU16 (); + m_flags = field & 0x3F; + m_length = field>>12; + m_windowSize = start.ReadNtohU16 (); + m_checksum = start.ReadNtohU16 (); + m_urgentPointer = start.ReadNtohU16 (); + return GetSerializedSize (); +} + + +}; // namespace ns3 diff --git a/src/internet-node/tcp-header.h b/src/internet-node/tcp-header.h new file mode 100644 index 000000000..610667dcf --- /dev/null +++ b/src/internet-node/tcp-header.h @@ -0,0 +1,161 @@ +/* -*- 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 + */ + +#ifndef TCP_HEADER_H +#define TCP_HEADER_H + +#include +#include "ns3/header.h" +#include "ns3/buffer.h" +#include "ns3/tcp.h" +#include "ns3/ipv4-address.h" +#include "sequence-number.h" + +namespace ns3 { + +class TcpHeader : public Header { +public: + static uint32_t GetUid (void); + + TcpHeader (); + virtual ~TcpHeader (); + + /** + * \brief Enable checksum calculation for TCP (XXX currently has no effect) + */ + static void EnableChecksums (void); +//Setters + /** + * \param port The source port for this TcpHeader + */ + void SetSourcePort (uint16_t port); + /** + * \param port the destination port for this TcpHeader + */ + void SetDestinationPort (uint16_t port); + /** + * \param sequenceNumber the sequence number for this TcpHeader + */ + void SetSequenceNumber (SequenceNumber sequenceNumber); + /** + * \param ackNumber the ACK number for this TcpHeader + */ + void SetAckNumber (SequenceNumber ackNumber); + /** + * \param length the length of this TcpHeader + */ + void SetLength (uint8_t length); + /** + * \param flags the flags for this TcpHeader + */ + void SetFlags (uint8_t flags); + /** + * \param windowSize the window size for this TcpHeader + */ + void SetWindowSize (uint16_t windowSize); + /** + * \param checksum the checksum for this TcpHeader + */ + void SetChecksum (uint16_t checksum); + /** + * \param urgentPointer the urgent pointer for this TcpHeader + */ + void SetUrgentPointer (uint16_t urgentPointer); + + +//Getters + /** + * \return The source port for this TcpHeader + */ + uint16_t GetSourcePort () const; + /** + * \return the destination port for this TcpHeader + */ + uint16_t GetDestinationPort () const; + /** + * \return the sequence number for this TcpHeader + */ + SequenceNumber GetSequenceNumber () const; + /** + * \return the ACK number for this TcpHeader + */ + SequenceNumber GetAckNumber () const; + /** + * \return the length of this TcpHeader + */ + uint8_t GetLength () const; + /** + * \return the flags for this TcpHeader + */ + uint8_t GetFlags () const; + /** + * \return the window size for this TcpHeader + */ + uint16_t GetWindowSize () const; + /** + * \return the checksum for this TcpHeader + */ + uint16_t GetChecksum () const; + /** + * \return the urgent pointer for this TcpHeader + */ + uint16_t GetUrgentPointer () const; + + /** + * \param source the ip source to use in the underlying + * ip packet. + * \param destination the ip destination to use in the + * underlying ip packet. + * \param protocol the protocol number to use in the underlying + * ip packet. + * + * If you want to use tcp checksums, you should call this + * method prior to adding the header to a packet. + */ + void InitializeChecksum (Ipv4Address source, + Ipv4Address destination, + uint8_t protocol); + + typedef enum { NONE = 0, FIN = 1, SYN = 2, RST = 4, PSH = 8, ACK = 16, + URG = 32} Flags_t; + + std::string GetName (void) const; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); + +private: + uint16_t m_sourcePort; + uint16_t m_destinationPort; + uint32_t m_sequenceNumber; + uint32_t m_ackNumber; + uint8_t m_length; // really a uint4_t + uint8_t m_flags; // really a uint6_t + uint16_t m_windowSize; + uint16_t m_checksum; + uint16_t m_urgentPointer; + + static bool m_calcChecksum; +}; + +}; // namespace ns3 + +#endif /* TCP_HEADER */ diff --git a/src/internet-node/tcp-impl.cc b/src/internet-node/tcp-impl.cc new file mode 100644 index 000000000..86807da7d --- /dev/null +++ b/src/internet-node/tcp-impl.cc @@ -0,0 +1,48 @@ +/* -*- 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 + */ +#include "tcp-impl.h" +#include "tcp-l4-protocol.h" +#include "ns3/socket.h" +#include "ns3/assert.h" + +namespace ns3 { + +TcpImpl::TcpImpl (Ptr tcp) + : m_tcp (tcp) +{} +TcpImpl::~TcpImpl () +{ + NS_ASSERT (m_tcp == 0); +} + +Ptr +TcpImpl::CreateSocket (void) +{ + return m_tcp->CreateSocket (); +} + +void +TcpImpl::DoDispose (void) +{ + m_tcp = 0; + Tcp::DoDispose (); +} + +} // namespace ns3 diff --git a/src/internet-node/tcp-impl.h b/src/internet-node/tcp-impl.h new file mode 100644 index 000000000..8c6630093 --- /dev/null +++ b/src/internet-node/tcp-impl.h @@ -0,0 +1,58 @@ +/* -*- 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 + */ +#ifndef TCP_IMPL_H +#define TCP_IMPL_H + +#include "ns3/tcp.h" +#include "ns3/ptr.h" + +namespace ns3 { + +class TcpL4Protocol; + +/** + * \ingroup InternetNode + * \defgroup Tcp Tcp + * + * \section Tcp Overview + * + * The TCP code in ns3::InternetNode is ported from the + * + * Georgia Tech Network Simulator (GTNetS). + * + * Most of the logic is in class ns3::TcpSocket. + */ +class TcpImpl : public Tcp +{ +public: + TcpImpl (Ptr tcp); + virtual ~TcpImpl (); + + virtual Ptr CreateSocket (void); + +protected: + virtual void DoDispose (void); +private: + Ptr m_tcp; +}; + +} // namespace ns3 + +#endif /* TCP_IMPL_H */ diff --git a/src/internet-node/tcp-l4-protocol.cc b/src/internet-node/tcp-l4-protocol.cc new file mode 100644 index 000000000..b0eaa075e --- /dev/null +++ b/src/internet-node/tcp-l4-protocol.cc @@ -0,0 +1,485 @@ +/* -*- 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 + */ + +#include "ns3/assert.h" +#include "ns3/log.h" +#include "ns3/nstime.h" + +#include "ns3/packet.h" +#include "ns3/node.h" + +#include "tcp-l4-protocol.h" +#include "tcp-header.h" +#include "ipv4-end-point-demux.h" +#include "ipv4-end-point.h" +#include "ipv4-l3-protocol.h" +#include "tcp-socket.h" + +#include "tcp-typedefs.h" + +#include +#include + +NS_LOG_COMPONENT_DEFINE ("TcpL4Protocol"); + +namespace ns3 { + +//State Machine things -------------------------------------------------------- +TcpStateMachine::TcpStateMachine() + : aT (LAST_STATE, StateActionVec_t(LAST_EVENT)), + eV (MAX_FLAGS) +{ + NS_LOG_FUNCTION; + + // 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 (SYN_RCVD, SYN_ACK_TX); //XXX hacked for now, should stay in listen and replicate + 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, NO_ACT); + 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 (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_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, NO_ACT); + 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 (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; + NS_LOG_PARAMS (this << s << e); + return aT[s][e]; +} + +Events_t TcpStateMachine::FlagsEvent (uint8_t f) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (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---------------------------------------------------------- + + +/* see http://www.iana.org/assignments/protocol-numbers */ +const uint8_t TcpL4Protocol::PROT_NUMBER = 6; + +TcpL4Protocol::TcpL4Protocol (Ptr node) + : Ipv4L4Protocol (PROT_NUMBER, 2), + m_node (node), + m_endPoints (new Ipv4EndPointDemux ()) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << node); + NS_LOG_LOGIC("Made a TcpL4Protocol "< +TcpL4Protocol::CreateSocket (void) +{ + NS_LOG_FUNCTION; + Ptr socket = Create (m_node, this); + return socket; +} + +Ipv4EndPoint * +TcpL4Protocol::Allocate (void) +{ + NS_LOG_FUNCTION; + return m_endPoints->Allocate (); +} + +Ipv4EndPoint * +TcpL4Protocol::Allocate (Ipv4Address address) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << address); + return m_endPoints->Allocate (address); +} + +Ipv4EndPoint * +TcpL4Protocol::Allocate (uint16_t port) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << port); + return m_endPoints->Allocate (port); +} + +Ipv4EndPoint * +TcpL4Protocol::Allocate (Ipv4Address address, uint16_t port) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << address << port); + return m_endPoints->Allocate (address, port); +} + +Ipv4EndPoint * +TcpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort, + Ipv4Address peerAddress, uint16_t peerPort) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << localAddress << localPort << peerAddress << peerPort); + return m_endPoints->Allocate (localAddress, localPort, + peerAddress, peerPort); +} + +void +TcpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << endPoint); + m_endPoints->DeAllocate (endPoint); +} + +void +TcpL4Protocol::Receive (Ptr packet, + Ipv4Address const &source, + Ipv4Address const &destination, + Ptr incomingInterface) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << packet << source << destination << incomingInterface); + + TcpHeader tcpHeader; + //these two do a peek, so that the packet can be forwarded up + packet->RemoveHeader (tcpHeader); + packet->AddHeader (tcpHeader); + NS_LOG_LOGIC ("TcpL4Protocol "<Lookup (destination, tcpHeader.GetDestinationPort (), + source, tcpHeader.GetSourcePort (),incomingInterface); + if (endPoints.empty ()) + { + NS_LOG_LOGIC (" No endpoints matched on TcpL4Protocol "<ForwardUp (packet, source, tcpHeader.GetSourcePort ()); + } +} + +void +TcpL4Protocol::Send (Ptr packet, + Ipv4Address saddr, Ipv4Address daddr, + uint16_t sport, uint16_t dport) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << packet << saddr << daddr << sport << dport); + + TcpHeader tcpHeader; + tcpHeader.SetDestinationPort (dport); + tcpHeader.SetSourcePort (sport); + tcpHeader.InitializeChecksum (saddr, + daddr, + PROT_NUMBER); + tcpHeader.SetFlags (TcpHeader::ACK); + tcpHeader.SetAckNumber (0); + + packet->AddHeader (tcpHeader); + + Ptr ipv4 = + m_node->QueryInterface (Ipv4L3Protocol::iid); + if (ipv4 != 0) + { + ipv4->Send (packet, saddr, daddr, PROT_NUMBER); + } +} + +void +TcpL4Protocol::SendPacket (Ptr packet, TcpHeader outgoingHeader, + Ipv4Address saddr, Ipv4Address daddr) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << packet << saddr << daddr); + // XXX outgoingHeader cannot be logged + + outgoingHeader.SetLength (5); //header length in units of 32bit words + outgoingHeader.SetChecksum (0); //XXX + outgoingHeader.SetUrgentPointer (0); //XXX + + packet->AddHeader (outgoingHeader); + + Ptr ipv4 = + m_node->QueryInterface (Ipv4L3Protocol::iid); + if (ipv4 != 0) + { + ipv4->Send (packet, saddr, daddr, PROT_NUMBER); + } + else + NS_FATAL_ERROR("Trying to use Tcp on a node without an Ipv4 interface"); +} + +}; // namespace ns3 + diff --git a/src/internet-node/tcp-l4-protocol.h b/src/internet-node/tcp-l4-protocol.h new file mode 100644 index 000000000..632d0e5ee --- /dev/null +++ b/src/internet-node/tcp-l4-protocol.h @@ -0,0 +1,111 @@ +/* -*- 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 + */ + +#ifndef TCP_L4_PROTOCOL_H +#define TCP_L4_PROTOCOL_H + +#include + +#include "ns3/packet.h" +#include "ns3/ipv4-address.h" +#include "ns3/ptr.h" +#include "ipv4-end-point-demux.h" +#include "ipv4-l4-protocol.h" +#include "ipv4-interface.h" + +#include "tcp-header.h" +#include "tcp-typedefs.h" + +namespace ns3 { + +class Node; +class TraceResolver; +class TraceContext; +class Socket; +class TcpHeader; +/** + * \brief Implementation of the TCP protocol + */ +class TcpL4Protocol : public Ipv4L4Protocol { +public: + static const uint8_t PROT_NUMBER; + /** + * \brief Constructor + * \param node The node this protocol is associated with + */ + TcpL4Protocol (Ptr node); + virtual ~TcpL4Protocol (); + + /** + * \return A smart Socket pointer to a TcpSocket, allocated by this instance + * of the TCP protocol + */ + Ptr CreateSocket (void); + + Ipv4EndPoint *Allocate (void); + Ipv4EndPoint *Allocate (Ipv4Address address); + Ipv4EndPoint *Allocate (uint16_t port); + Ipv4EndPoint *Allocate (Ipv4Address address, uint16_t port); + Ipv4EndPoint *Allocate (Ipv4Address localAddress, uint16_t localPort, + Ipv4Address peerAddress, uint16_t peerPort); + + void DeAllocate (Ipv4EndPoint *endPoint); + +// // called by TcpSocket. +// bool Connect (const Ipv4Address& saddr, const Ipv4Address& daddr, +// uint16_t sport, uint16_t dport); + + /** + * \brief Send a packet via TCP + * \param packet The packet to send + * \param saddr The source Ipv4Address + * \param daddr The destination Ipv4Address + * \param sport The source port number + * \param dport The destination port number + */ + void Send (Ptr packet, + Ipv4Address saddr, Ipv4Address daddr, + uint16_t sport, uint16_t dport); + /** + * \brief Recieve a packet up the protocol stack + * \param p The Packet to dump the contents into + * \param source The source's Ipv4Address + * \param destination The destinations Ipv4Address + * \param incomingInterface The Ipv4Interface it was received on + */ + virtual void Receive (Ptr p, + Ipv4Address const &source, + Ipv4Address const &destination, + Ptr incomingInterface); + +protected: + virtual void DoDispose (void); +private: + Ptr m_node; + Ipv4EndPointDemux *m_endPoints; +private: + friend class TcpSocket; + void SendPacket (Ptr, TcpHeader, + Ipv4Address, Ipv4Address); +}; + +}; // namespace ns3 + +#endif /* TCP_L4_PROTOCOL_H */ diff --git a/src/internet-node/tcp-socket.cc b/src/internet-node/tcp-socket.cc new file mode 100644 index 000000000..a910fb53d --- /dev/null +++ b/src/internet-node/tcp-socket.cc @@ -0,0 +1,1077 @@ +/* -*- 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 + */ + + +#include "ns3/node.h" +#include "ns3/inet-socket-address.h" +#include "ns3/log.h" +#include "ns3/ipv4.h" +#include "tcp-socket.h" +#include "tcp-l4-protocol.h" +#include "ipv4-end-point.h" +#include "ipv4-l4-demux.h" +#include "ns3/simulation-singleton.h" +#include "tcp-typedefs.h" +#include "ns3/simulator.h" +#include "ns3/packet.h" +#include "ns3/default-value.h" + +#include + +NS_LOG_COMPONENT_DEFINE ("TcpSocket"); + +using namespace std; + +namespace ns3 { + +TcpSocket::TcpSocket (Ptr node, Ptr tcp) + : m_skipRetxResched (false), + m_dupAckCount (0), + m_endPoint (0), + m_node (node), + m_tcp (tcp), + m_errno (ERROR_NOTERROR), + m_shutdownSend (false), + m_shutdownRecv (false), + m_connected (false), + m_state (CLOSED), + m_closeNotified (false), + m_closeRequestNotified (false), + m_closeOnEmpty (false), + m_nextTxSequence (0), + m_highTxMark (0), + m_highestRxAck (0), + m_lastRxAck (0), + m_nextRxSequence (0), + m_pendingData (0), + m_segmentSize (Tcp::defaultSegSize.GetValue()), + m_rxWindowSize (Tcp::defaultAdvWin.GetValue()), + m_advertisedWindowSize (Tcp::defaultAdvWin.GetValue()), + m_cWnd (Tcp::defaultInitialCWnd.GetValue() * m_segmentSize), + m_ssThresh (Tcp::defaultSSThresh.GetValue()), + m_initialCWnd (Tcp::defaultInitialCWnd.GetValue()), + m_rtt (RttEstimator::CreateDefault()), + m_lastMeasuredRtt (Seconds(0.0)), + m_cnTimeout (Seconds (Tcp::defaultConnTimeout.GetValue ())), + m_cnCount (Tcp::defaultConnCount.GetValue ()) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this<DeAllocate (m_endPoint); + NS_ASSERT (m_endPoint == 0); + } + m_tcp = 0; + delete m_pendingData; //prevents leak +} + +enum Socket::SocketErrno +TcpSocket::GetErrno (void) const +{ + NS_LOG_FUNCTION; + return m_errno; +} + +Ptr +TcpSocket::GetNode (void) const +{ + NS_LOG_FUNCTION; + return m_node; +} + +void +TcpSocket::Destroy (void) +{ + NS_LOG_FUNCTION; + m_node = 0; + m_endPoint = 0; + m_tcp = 0; +} +int +TcpSocket::FinishBind (void) +{ + NS_LOG_FUNCTION; + if (m_endPoint == 0) + { + return -1; + } + m_endPoint->SetRxCallback (MakeCallback (&TcpSocket::ForwardUp, this)); + m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocket::Destroy, this)); + return 0; +} + +int +TcpSocket::Bind (void) +{ + NS_LOG_FUNCTION; + m_endPoint = m_tcp->Allocate (); + return FinishBind (); +} +int +TcpSocket::Bind (const Address &address) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this<Allocate (); + NS_LOG_LOGIC ("TcpSocket "<Allocate (port); + NS_LOG_LOGIC ("TcpSocket "<Allocate (ipv4); + NS_LOG_LOGIC ("TcpSocket "<Allocate (ipv4, port); + NS_LOG_LOGIC ("TcpSocket "<Size () != 0 ) + { + m_closeOnEmpty = true; + return 0; + } + } + ProcessAction (action); + ShutdownSend (); + return 0; +} + +int +TcpSocket::Connect (const Address & address) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << address); + if (m_endPoint == 0) + { + if (Bind () == -1) + { + NS_ASSERT (m_endPoint == 0); + return -1; + } + NS_ASSERT (m_endPoint != 0); + } + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); + m_defaultAddress = transport.GetIpv4 (); + m_defaultPort = transport.GetPort (); + + uint32_t localIfIndex; + Ptr ipv4 = m_node->QueryInterface (Ipv4::iid); + + if (ipv4->GetIfIndexForDestination (m_defaultAddress, localIfIndex)) + { + m_endPoint->SetLocalAddress (ipv4->GetAddress (localIfIndex)); + } + else + { + m_errno = ERROR_NOROUTETOHOST; + return -1; + } + + Actions_t action = ProcessEvent (APP_CONNECT); + bool success = ProcessAction (action); + if (success) + { + return 0; + } + return -1; +} +int +TcpSocket::Send (const Ptr p) //p here is just data, no headers +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << p); + if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT) + { // Ok to buffer some data to send + if (!m_pendingData) + { + m_pendingData = new PendingData (0); // Create if non-existent + m_firstPendingSequence = m_nextTxSequence; // Note seq of first + } + //PendingData::Add always copies the data buffer, never modifies + m_pendingData->Add (p->GetSize (), p->PeekData ()); + Actions_t action = ProcessEvent (APP_SEND); + if (!ProcessAction (action)) + { + return -1; // Failed, return zero + } + return p->GetSize (); + } + else + { + m_errno = ERROR_NOTCONN; + return -1; + } +} + +int TcpSocket::Send (const uint8_t* buf, uint32_t size) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << buf << size); + if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT) + { // Ok to buffer some data to send + if (!m_pendingData) + { + m_pendingData = new PendingData (); // Create if non-existent + m_firstPendingSequence = m_nextTxSequence; // Note seq of first + } + //PendingData::Add always copies the data buffer, never modifies + m_pendingData->Add (size,buf); + Actions_t action = ProcessEvent (APP_SEND); + if (!ProcessAction (action)) + { + return -1; // Failed, return zero + } + return size; + } + else + { + m_errno = ERROR_NOTCONN; + return -1; + } +} + +int TcpSocket::DoSendTo (Ptr p, const Address &address) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << p << address); + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); + Ipv4Address ipv4 = transport.GetIpv4 (); + uint16_t port = transport.GetPort (); + return DoSendTo (p, ipv4, port); +} + +int TcpSocket::DoSendTo (Ptr p, Ipv4Address ipv4, uint16_t port) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << p << ipv4 << port); + if (m_endPoint == 0) + { + if (Bind () == -1) + { + NS_ASSERT (m_endPoint == 0); + return -1; + } + NS_ASSERT (m_endPoint != 0); + } + if (m_shutdownSend) + { + m_errno = ERROR_SHUTDOWN; + return -1; + } + m_tcp->Send (p, m_endPoint->GetLocalAddress (), ipv4, + m_endPoint->GetLocalPort (), port); + NotifyDataSent (p->GetSize ()); + return 0; +} + +int +TcpSocket::SendTo (const Address &address, Ptr p) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << address << p); + if (!m_connected) + { + m_errno = ERROR_NOTCONN; + return -1; + } + else + { + return Send (p); //drop the address according to BSD manpages + } +} + +int +TcpSocket::Listen (uint32_t q) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << q); + Actions_t action = ProcessEvent (APP_LISTEN); + ProcessAction (action); + return 0; +} + +void +TcpSocket::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << packet << ipv4 << port); + if (m_shutdownRecv) + { + return; + } + TcpHeader tcpHeader; + packet->RemoveHeader (tcpHeader); + + if (tcpHeader.GetFlags () & TcpHeader::ACK) + { + Time m = m_rtt->AckSeq (tcpHeader.GetAckNumber () ); + if (m != Seconds (0.0)) + { + m_lastMeasuredRtt = m; + } + } + + Events_t event = SimulationSingleton::Get ()->FlagsEvent (tcpHeader.GetFlags () ); + Actions_t action = ProcessEvent (event); //updates the state + Address address = InetSocketAddress (ipv4, port); + ProcessPacketAction (action, packet, tcpHeader, address); +} + +Actions_t TcpSocket::ProcessEvent (Events_t e) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << e); + States_t saveState = m_state; + NS_LOG_LOGIC ("TcpSocket " << this << " processing event " << e); + // simulation singleton is a way to get a single global static instance of a + // class intended to be a singleton; see simulation-singleton.h + SA stateAction = SimulationSingleton::Get ()->Lookup (m_state,e); + // debug + if (stateAction.action == RST_TX) + { + NS_LOG_LOGIC ("TcpSocket " << this << " sending RST from state " + << saveState << " event " << e); + } + bool needCloseNotify = (stateAction.state == CLOSED && m_state != CLOSED + && e != TIMEOUT); + m_state = stateAction.state; + NS_LOG_LOGIC ("TcpSocket " << this << " moved from state " << saveState + << " to state " <SetPeer (m_defaultAddress, m_defaultPort); + NS_LOG_LOGIC ("TcpSocket " << this << " Connected!"); + } + if (needCloseNotify && !m_closeNotified) + { + NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from " + << m_state << " event " << e << " closeNot " << m_closeNotified + << " action " << stateAction.action); + NotifyCloseCompleted (); + m_closeNotified = true; + NS_LOG_LOGIC ("TcpSocket " << this << " calling Closed from PE" + << " origState " << saveState + << " event " << e); + NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from " + << m_state << " event " << e + << " set CloseNotif "); + } + return stateAction.action; +} + +void TcpSocket::SendEmptyPacket (uint8_t flags) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << flags); + Ptr p = Create (); + TcpHeader header; + + header.SetFlags (flags); + header.SetSequenceNumber (m_nextTxSequence); + header.SetAckNumber (m_nextRxSequence); + header.SetSourcePort (m_endPoint->GetLocalPort ()); + header.SetDestinationPort (m_defaultPort); + header.SetWindowSize (m_advertisedWindowSize); + m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (), + m_defaultAddress); + Time rto = m_rtt->RetransmitTimeout (); + if (flags & TcpHeader::SYN) + { + rto = m_cnTimeout; + m_cnCount--; + } + if (m_retxEvent.IsExpired () ) //no outstanding timer + { + NS_LOG_LOGIC ("Schedule retransmission timeout at time " + << Simulator::Now ().GetSeconds () << " to expire at time " + << (Simulator::Now () + rto).GetSeconds ()); + m_retxEvent = Simulator::Schedule (rto, &TcpSocket::ReTxTimeout, this); + } +} + +bool TcpSocket::ProcessAction (Actions_t a) +{ // These actions do not require a packet or any TCP Headers + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << a); + switch (a) + { + case NO_ACT: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action: NO_ACT"); + break; + case ACK_TX: + SendEmptyPacket (TcpHeader::ACK); + break; + case ACK_TX_1: + NS_ASSERT (false); // This should be processed in ProcessPacketAction + break; + case RST_TX: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action RST_TX"); + SendEmptyPacket (TcpHeader::RST); + break; + case SYN_TX: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_TX"); + // TCP SYN Flag consumes one byte + m_nextTxSequence+= 1; + SendEmptyPacket (TcpHeader::SYN); + break; + case SYN_ACK_TX: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX"); + SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); + break; + case FIN_TX: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_TX"); + SendEmptyPacket (TcpHeader::FIN); + break; + case FIN_ACK_TX: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_ACK_TX"); + SendEmptyPacket (TcpHeader::FIN | TcpHeader::ACK); + break; + case NEW_ACK: + NS_ASSERT (false); // This should be processed in ProcessPacketAction + break; + case NEW_SEQ_RX: + NS_ASSERT (false); // This should be processed in ProcessPacketAction + break; + case RETX: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action RETX"); + break; + case TX_DATA: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action TX_DATA"); + SendPendingData (); + break; + case PEER_CLOSE: + NS_ASSERT (false); // This should be processed in ProcessPacketAction + NS_LOG_LOGIC ("TcpSocket " << this <<" Action PEER_CLOSE"); + break; + case APP_CLOSED: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_CLOSED"); + break; + case CANCEL_TM: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action CANCEL_TM"); + break; + case APP_NOTIFY: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_NOTIFY"); + break; + case SERV_NOTIFY: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action SERV_NOTIFY"); + NS_LOG_LOGIC ("TcpSocket " << this << " Connected!"); + NotifyConnectionSucceeded (); + m_connected = true; // ! This is bogus; fix when we clone the tcp + m_endPoint->SetPeer (m_defaultAddress, m_defaultPort); + break; + case LAST_ACTION: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action LAST_ACTION"); + break; + } + return true; +} + +bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, + const TcpHeader& tcpHeader, + const Address& fromAddress) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << p << "tcpHeader " << fromAddress); + uint32_t localIfIndex; + Ptr ipv4 = m_node->QueryInterface (Ipv4::iid); + switch (a) + { + case SYN_ACK_TX: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX"); + m_defaultPort = InetSocketAddress::ConvertFrom (fromAddress).GetPort (); + m_defaultAddress = + InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 (); + m_endPoint->SetPeer (m_defaultAddress, m_defaultPort); + if (ipv4->GetIfIndexForDestination (m_defaultAddress, localIfIndex)) + { + m_endPoint->SetLocalAddress (ipv4->GetAddress (localIfIndex)); + } + // TCP SYN consumes one byte + m_nextRxSequence++; + SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); + break; + case ACK_TX_1: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action ACK_TX_1"); + // TCP SYN consumes one byte + m_nextRxSequence++; + SendEmptyPacket (TcpHeader::ACK); + m_rxWindowSize = tcpHeader.GetWindowSize (); + if (tcpHeader.GetAckNumber () > m_highestRxAck) + { + m_highestRxAck = tcpHeader.GetAckNumber (); + } + SendPendingData (); + break; + case NEW_ACK: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_ACK_TX"); + if (tcpHeader.GetAckNumber () < m_highestRxAck) //old ack, do nothing + { + break; + } + if (tcpHeader.GetAckNumber () == m_highestRxAck && + tcpHeader.GetAckNumber () < m_nextTxSequence) + { + DupAck (tcpHeader, ++m_dupAckCount); + break; + } + if (tcpHeader.GetAckNumber () > m_highestRxAck) + { + m_dupAckCount = 0; + } + NewAck (tcpHeader.GetAckNumber ()); + break; + case NEW_SEQ_RX: + NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_SEQ_TX"); + NewRx (p, tcpHeader, fromAddress); // Process new data received + break; + case PEER_CLOSE: + { + // First we have to be sure the FIN packet was not received + // out of sequence. If so, note pending close and process + // new sequence rx + if (tcpHeader.GetSequenceNumber () != m_nextRxSequence) + { // process close later + m_pendingClose = true; + NS_LOG_LOGIC ("TcpSocket " << this << " setting pendingClose" + << " rxseq " << tcpHeader.GetSequenceNumber () + << " nextRxSeq " << m_nextRxSequence); + NewRx (p, tcpHeader, fromAddress); + return true; + } + // Now we need to see if any data came with the FIN + // if so, call NewRx + if (p->GetSize () != 0) + { + NewRx (p, tcpHeader, fromAddress); + } + States_t saveState = m_state; // Used to see if app responds + NS_LOG_LOGIC ("TcpSocket " << this + << " peer close, state " << m_state); + if (!m_closeRequestNotified) + { + NS_LOG_LOGIC ("TCP " << this + << " calling AppCloseRequest"); + NotifyCloseRequested (); + m_closeRequestNotified = true; + } + NS_LOG_LOGIC ("TcpSocket " << this + << " peer close, state after " << m_state); + if (m_state == saveState) + { // Need to ack, the application will close later + SendEmptyPacket (TcpHeader::ACK); + // Also need to re-tx the ack if we + } + if (m_state == LAST_ACK) + { + NS_LOG_LOGIC ("TcpSocket " << this << " scheduling LATO1"); + m_lastAckEvent = Simulator::Schedule (m_rtt->RetransmitTimeout (), + &TcpSocket::LastAckTimeout,this); + } + break; + } + default: + break; + } + return true; +} + +bool TcpSocket::SendPendingData (bool withAck) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << withAck); + NS_LOG_LOGIC ("ENTERING SendPendingData"); + if (!m_pendingData) + { + return false; // No data exists + } + uint32_t nPacketsSent = 0; + while (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence)) + { + uint32_t w = AvailableWindow ();// Get available window size + NS_LOG_LOGIC ("TcpSocket " << this << " SendPendingData" + << " w " << w + << " rxwin " << m_rxWindowSize + << " cWnd " << m_cWnd + << " segsize " << m_segmentSize + << " nextTxSeq " << m_nextTxSequence + << " highestRxAck " << m_highestRxAck + << " pd->Size " << m_pendingData->Size () + << " pd->SFS " << m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence)); + + if (w < m_segmentSize && m_pendingData->Size () > w) + { + break; // No more + } + uint32_t s = std::min (w, m_segmentSize); // Send no more than window + PendingData* d = m_pendingData->CopyFromSeq (s, m_firstPendingSequence, + m_nextTxSequence); + NS_LOG_LOGIC("TcpSocket " << this << " sendPendingData" + << " txseq " << m_nextTxSequence + << " s " << s + << " datasize " << d->Size() ); + uint8_t flags = 0; + if (withAck) + { + flags |= TcpHeader::ACK; + } + uint32_t sz = d->Size (); // Size of packet + uint32_t remainingData = m_pendingData->SizeFromSeq( + m_firstPendingSequence, + m_nextTxSequence + SequenceNumber (sz)); + if (m_closeOnEmpty && (remainingData == 0)) + { + flags = TcpHeader::FIN; + m_state = FIN_WAIT_1; + } + // Create and send the packet + + Ptr p = Create (d->data, sz); + + TcpHeader header; + header.SetFlags (flags); + header.SetSequenceNumber (m_nextTxSequence); + header.SetAckNumber (m_nextRxSequence); + header.SetSourcePort (m_endPoint->GetLocalPort()); + header.SetDestinationPort (m_defaultPort); + if (m_shutdownSend) + { + m_errno = ERROR_SHUTDOWN; + return -1; + } + + Time rto = m_rtt->RetransmitTimeout (); + if (m_retxEvent.IsExpired () ) //go ahead and schedule the retransmit + { + NS_LOG_LOGIC ("Schedule retransmission timeout at time " << + Simulator::Now ().GetSeconds () << " to expire at time " << + (Simulator::Now () + rto).GetSeconds () ); + m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this); + } + NS_LOG_LOGIC ("About to send a packet with flags: " << flags); + m_tcp->SendPacket (p, header, + m_endPoint->GetLocalAddress (), + m_defaultAddress); + m_rtt->SentSeq(m_nextTxSequence, sz); // notify the RTT + NotifyDataSent (p->GetSize () ); // notify the application + nPacketsSent++; // Count sent this loop + m_nextTxSequence += sz; // Advance next tx sequence + m_highTxMark = std::max (m_nextTxSequence, m_highTxMark);// Note the high water mark + } + NS_LOG_LOGIC ("Sent "<0); +} + +uint32_t TcpSocket::UnAckDataCount () +{ + NS_LOG_FUNCTION; + return m_nextTxSequence - m_highestRxAck; +} + +uint32_t TcpSocket::BytesInFlight () +{ + NS_LOG_FUNCTION; + return m_highTxMark - m_highestRxAck; +} + +uint32_t TcpSocket::Window () +{ + NS_LOG_FUNCTION; + NS_LOG_LOGIC ("TcpSocket::Window() "< p, + const TcpHeader& tcpHeader, + const Address& fromAddress) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << p << "tcpHeader " << fromAddress); + NS_LOG_LOGIC ("TcpSocket " << this << " NewRx, p.size is " << p->GetSize () ); + States_t origState = m_state; + uint32_t s = p->GetSize (); // Size of associated data + if (s == 0) + {// Nothing to do if no associated data + return; + } + // Log sequence received if enabled + // NoteTimeSeq(LOG_SEQ_RX, h->sequenceNumber); + // Three possibilities + // 1) Received seq is expected, deliver this and any buffered data + // 2) Received seq is < expected, just re-ack previous + // 3) Received seq is > expected, just re-ack previous and buffer data + if (tcpHeader.GetSequenceNumber () == m_nextRxSequence) + { // If seq is expected seq + // 1) Update nextRxSeq + // 2) Deliver to application this packet + // 3) See if any buffered can be delivered + // 4) Send the ack + m_nextRxSequence += s; // Advance next expected sequence + //bytesReceived += s; // Statistics + NS_LOG_LOGIC("Case 1, advanced nrxs to " << m_nextRxSequence ); + NotifyDataReceived (p, fromAddress); + if (m_closeNotified) + { + NS_LOG_LOGIC ("Tcp " << this << " HuH? Got data after closeNotif"); + } + NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq by " << s); + // Look for buffered data + UnAckData_t::iterator i; + // Note that the bufferedData list DOES contain the tcp header + while (!m_bufferedData.empty ()) + { // Check the buffered data for delivery + NS_LOG_LOGIC("TCP " << this << " bufferedData.size() " + << m_bufferedData.size () + << " time " << Simulator::Now ()); + i = m_bufferedData.begin (); + Ptr p1 = i->second; + SequenceNumber s1 = 0; + if (i->first > m_nextRxSequence) + { + break; // Not next expected + } + // already have the header as a param + //TCPHeader* h = dynamic_cast(p1->PopPDU()); + // Check non-null here... + uint8_t flags = tcpHeader.GetFlags (); // Flags (used below) + if (i->first < m_nextRxSequence) + { // remove already delivered data + // Two cases here. + // 1) seq + length <= nextRxSeq, just discard + // 2) seq + length > nextRxSeq, can deliver partial + s1 = p->GetSize (); + if (i->first + s1 < m_nextRxSequence) + { // Just remove from list + //bufferedData.erase(i); + p1 = 0; // Nothing to deliver + } + else + { // Remove partial data to prepare for delivery + uint32_t dup = m_nextRxSequence - i->first; + i->second = p1->CreateFragment (0, p1->GetSize () - dup); + p1 = i->second; + } + } + else + { // At this point i->first must equal nextRxSeq + if (i->first != m_nextRxSequence) + { + NS_FATAL_ERROR ("HuH? NexRx failure, first " + << i->first << " nextRxSeq " << m_nextRxSequence); + } + s1 = p1->GetSize (); + } + NotifyDataReceived (p1, fromAddress); + + NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq1 by " << s1 ); + m_nextRxSequence += s1; // Note data received + m_bufferedData.erase (i); // Remove from list + if (flags & TcpHeader::FIN) + NS_LOG_LOGIC("TcpSocket " << this + << " found FIN in buffered"); + } + + if (m_pendingClose || (origState > ESTABLISHED)) + { // See if we can close now + if (m_bufferedData.empty()) + { + ProcessPacketAction (PEER_CLOSE, p, tcpHeader, fromAddress); + } + } + } + else if (SequenceNumber (tcpHeader.GetSequenceNumber ()) >= m_nextRxSequence) + { // Need to buffer this one + NS_LOG_LOGIC ("Case 2, buffering " << tcpHeader.GetSequenceNumber () ); + UnAckData_t::iterator i = + m_bufferedData.find (tcpHeader.GetSequenceNumber () ); + if (i != m_bufferedData.end () ) + { + i->second = 0; // relase reference to already buffered + } + // Save for later delivery + m_bufferedData[tcpHeader.GetSequenceNumber () ] = p; + } + else + { // debug + NS_LOG_LOGIC("TCP " << this + << " got seq " << tcpHeader.GetSequenceNumber () + << " expected " << m_nextRxSequence + << " flags " << tcpHeader.GetFlags ()); + } + // Now send a new ack packet acknowledging all received and delivered data + SendEmptyPacket (TcpHeader::ACK); +} + + +void TcpSocket::CommonNewAck (SequenceNumber ack, bool skipTimer) +{ // CommonNewAck is called only for "New" (non-duplicate) acks + // and MUST be called by any subclass, from the NewAck function + // Always cancel any pending re-tx timer on new acknowledgement + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << ack << skipTimer); + //DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl)); + if (!skipTimer) + { + m_retxEvent.Cancel (); + } + uint32_t numberAck = ack - m_highestRxAck; // Number bytes ack'ed + NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack + << " numberAck " << numberAck); + m_highestRxAck = ack; // Note the highest recieved Ack + if (ack > m_nextTxSequence) + { + m_nextTxSequence = ack; // If advanced + } + // See if all pending ack'ed; if so we can delete the data + if (m_pendingData) + { // Data exists, see if can be deleted + if (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_highestRxAck) == 0) + { // All pending acked, can be deleted + m_pendingData->Clear (); + delete m_pendingData; + m_pendingData = 0; + // Insure no re-tx timer + m_retxEvent.Cancel(); + } + } + // Try to send more data + SendPendingData(); +} + +void TcpSocket::NewAck (SequenceNumber seq) +{ // New acknowledgement up to sequence number "seq" + // Adjust congestion window in response to new ack's received + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << seq); + NS_LOG_LOGIC ("TcpSocket " << this << " NewAck " + << " seq " << seq + << " cWnd " << m_cWnd + << " ssThresh " << m_ssThresh); + if (m_cWnd < m_ssThresh) + { // Slow start mode, add one segSize to cWnd + m_cWnd += m_segmentSize; + NS_LOG_LOGIC ("TcpSocket " << this << " NewCWnd SlowStart, cWnd " << m_cWnd + << " sst " << m_ssThresh); + } + else + { // Congestion avoidance mode, adjust by (ackBytes*segSize) / cWnd + double adder = ((double) m_segmentSize * m_segmentSize) / m_cWnd; + if (adder < 1.0) + { + adder = 1.0; + } + m_cWnd += (uint32_t) adder; + NS_LOG_LOGIC ("NewCWnd CongAvoid, cWnd " << m_cWnd + << " sst " << m_ssThresh); + } + CommonNewAck (seq, false); // Complete newAck processing +} + +void TcpSocket::DupAck (const TcpHeader& t, uint32_t count) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this << "t " << count); + NS_LOG_LOGIC ("TcpSocket " << this << " DupAck " << t.GetAckNumber () + << ", count " << count + << ", time " << Simulator::Now ()); + if (count == 3) + { // Count of three indicates triple duplicate ack + m_ssThresh = Window () / 2; // Per RFC2581 + m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize); + NS_LOG_LOGIC("TcpSocket " << this << "Tahoe TDA, time " << Simulator::Now () + << " seq " << t.GetAckNumber () + << " in flight " << BytesInFlight () + << " new ssthresh " << m_ssThresh); + + m_cWnd = m_segmentSize; // Collapse cwnd (re-enter slowstart) + // For Tahoe, we also reset nextTxSeq + m_nextTxSequence = m_highestRxAck; + SendPendingData (); + } +} + +void TcpSocket::ReTxTimeout () +{ // Retransmit timeout + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this); + m_ssThresh = Window () / 2; // Per RFC2581 + m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize); + // Set cWnd to segSize on timeout, per rfc2581 + // Collapse congestion window (re-enter slowstart) + m_cWnd = m_segmentSize; + m_nextTxSequence = m_highestRxAck; // Start from highest Ack + m_rtt->IncreaseMultiplier (); // Double timeout value for next retx timer + Retransmit (); // Retransmit the packet +} + +void TcpSocket::LastAckTimeout () +{ + m_lastAckEvent.Cancel (); + if (m_state == LAST_ACK) + { + Actions_t action = ProcessEvent (TIMEOUT); + ProcessAction (action); + } + if (!m_closeNotified) + { + m_closeNotified = true; + } +} + +void TcpSocket::Retransmit () +{ + NS_LOG_FUNCTION; + NS_LOG_PARAMS (this); + uint8_t flags = TcpHeader::NONE; + if (m_state == SYN_SENT) + { + if (m_cnCount > 0) + { + SendEmptyPacket (TcpHeader::SYN); + return; + } + else + { + NotifyConnectionFailed (); + return; + } + } + if (!m_pendingData) + { + if (m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2) + { // Must have lost FIN, re-send + SendEmptyPacket (TcpHeader::FIN); + } + return; + } + PendingData* d = m_pendingData->CopyFromSeq (m_segmentSize, + m_firstPendingSequence, + m_highestRxAck); + // Calculate remaining data for COE check + uint32_t remainingData = + m_pendingData->SizeFromSeq (m_firstPendingSequence, + m_nextTxSequence + SequenceNumber(d->Size ())); + if (m_closeOnEmpty && remainingData == 0) + { // Add the FIN flag + flags = flags | TcpHeader::FIN; + } + Ptr p = Create (d->data, d->Size()); + NS_LOG_LOGIC ("TcpSocket " << this << " retxing seq " << m_highestRxAck); + if (m_retxEvent.IsExpired () ) + { + Time rto = m_rtt->RetransmitTimeout (); + NS_LOG_LOGIC ("Schedule retransmission timeout at time " + << Simulator::Now ().GetSeconds () << " to expire at time " + << (Simulator::Now () + rto).GetSeconds ()); + m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this); + } + m_rtt->SentSeq (m_highestRxAck,d->Size ()); + // And send the packet + TcpHeader tcpHeader; + tcpHeader.SetSequenceNumber (m_nextTxSequence); + tcpHeader.SetAckNumber (m_nextRxSequence); + tcpHeader.SetSourcePort (m_endPoint->GetLocalPort()); + tcpHeader.SetDestinationPort (m_defaultPort); + tcpHeader.SetFlags (flags); + tcpHeader.SetWindowSize (m_advertisedWindowSize); + + m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (), + m_defaultAddress); +} + +}//namespace ns3 diff --git a/src/internet-node/tcp-socket.h b/src/internet-node/tcp-socket.h new file mode 100644 index 000000000..8809ed961 --- /dev/null +++ b/src/internet-node/tcp-socket.h @@ -0,0 +1,161 @@ +/* -*- 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 + */ +#ifndef TCP_SOCKET_H +#define TCP_SOCKET_H + +#include +#include "ns3/callback.h" +#include "ns3/socket.h" +#include "ns3/ptr.h" +#include "ns3/ipv4-address.h" +#include "ns3/event-id.h" +#include "tcp-typedefs.h" +#include "pending-data.h" +#include "sequence-number.h" +#include "rtt-estimator.h" + +namespace ns3 { + +class Ipv4EndPoint; +class Node; +class Packet; +class TcpL4Protocol; +class TcpHeader; + +class TcpSocket : public Socket +{ +public: + /** + * Create an unbound tcp socket. + */ + TcpSocket (Ptr node, Ptr tcp); + virtual ~TcpSocket (); + + virtual enum SocketErrno GetErrno (void) const; + virtual Ptr 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 Send (Ptr p); + virtual int Send (const uint8_t* buf, uint32_t size); + virtual int SendTo(const Address &address, Ptr p); + virtual int Listen(uint32_t queueLimit); + +private: + friend class Tcp; + // invoked by Tcp class + int FinishBind (void); + void ForwardUp (Ptr p, Ipv4Address ipv4, uint16_t port); + void Destroy (void); + int DoSendTo (Ptr p, const Address &daddr); + int DoSendTo (Ptr p, Ipv4Address daddr, uint16_t dport); + void SendEmptyPacket(uint8_t flags); + //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 p, + const TcpHeader& tcpHeader, + const Address& fromAddress); + Actions_t ProcessEvent (Events_t e); + bool SendPendingData(bool withAck = false); + + //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 + + // Manage data tx/rx + void NewRx (Ptr, const TcpHeader&, const Address&); + // XXX This should be virtual and overridden + void NewAck (SequenceNumber seq); + // XXX This should be virtual and overridden + void DupAck (const TcpHeader& t, uint32_t count); + void ReTxTimeout (); + void LastAckTimeout (); + void Retransmit (); + void CommonNewAck (SequenceNumber seq, bool skipTimer = false); + + bool m_skipRetxResched; + uint32_t m_dupAckCount; + EventId m_retxEvent; + EventId m_lastAckEvent; + + Ipv4EndPoint *m_endPoint; + Ptr m_node; + Ptr m_tcp; + Ipv4Address m_defaultAddress; + uint16_t m_defaultPort; + Callback, uint32_t, const Address &> m_dummyRxCallback; + Callback, uint8_t const*, uint32_t, const Address &> + m_rxCallback; + enum SocketErrno m_errno; + bool m_shutdownSend; + bool m_shutdownRecv; + bool m_connected; + + //manage the state infomation + States_t m_state; + bool m_closeNotified; + bool m_closeRequestNotified; + bool m_closeOnEmpty; + bool m_pendingClose; + + + //sequence info, sender side + SequenceNumber m_nextTxSequence; + SequenceNumber m_highTxMark; + SequenceNumber m_highestRxAck; + SequenceNumber m_lastRxAck; + + //sequence info, reciever side + SequenceNumber m_nextRxSequence; + SequenceNumber m_nextAckSequence; + + //history data + UnAckData_t m_bufferedData; + PendingData* m_pendingData; + SequenceNumber m_firstPendingSequence; + + // Window management + uint32_t m_segmentSize; // SegmentSize + uint32_t m_rxWindowSize; + uint32_t m_advertisedWindowSize; // Window to advertise to peer + uint32_t m_cWnd; // Congestion window + uint32_t m_ssThresh; // Slow Start Threshold + uint32_t m_initialCWnd; // Initial (and reset) value for cWnd + + // Round trip time estimation + Ptr m_rtt; + Time m_lastMeasuredRtt; + + // Timer-related members + Time m_cnTimeout; + uint32_t m_cnCount; + +}; + +}//namespace ns3 + +#endif /* UDP_SOCKET_H */ diff --git a/src/internet-node/tcp-typedefs.h b/src/internet-node/tcp-typedefs.h new file mode 100644 index 000000000..277511c26 --- /dev/null +++ b/src/internet-node/tcp-typedefs.h @@ -0,0 +1,111 @@ +/* -*- 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 + * typedefs for tcp state machine + */ + +#include +#include +#include "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 + RST_RX, // 11 + BAD_FLAGS, // 12 + LAST_EVENT } Events_t; + +typedef enum { + NO_ACT, // 0 + ACK_TX, // 1 + ACK_TX_1, // ACK response to syn + RST_TX, // 2 + SYN_TX, // 3 + SYN_ACK_TX, // 4 + FIN_TX, // 5 + FIN_ACK_TX, // 6 + NEW_ACK, // 7 + NEW_SEQ_RX, // 8 + RETX, // 9 + TX_DATA, // 10 + PEER_CLOSE, // 11 + APP_CLOSED, // 12 + CANCEL_TM, // 13 + APP_NOTIFY, // 14 - Notify app that connection failed + SERV_NOTIFY, // 15 - Notify server tcp that connection completed + 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 StateActionVec_t; +typedef std::vector StateActions_t; // One per current state +typedef std::vector EventVec_t; // For flag events lookup + +//type for managing buffered out of sequence data +typedef std::map > 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 diff --git a/src/internet-node/wscript b/src/internet-node/wscript index 3bb60d1bb..7c09d9755 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -9,23 +9,30 @@ def build(bld): 'ipv4-l4-protocol.cc', 'ipv4-header.cc', 'udp-header.cc', + 'tcp-header.cc', 'ipv4-checksum.cc', 'ipv4-interface.cc', 'ipv4-l3-protocol.cc', 'ipv4-static-routing.cc', 'ipv4-end-point.cc', 'udp-l4-protocol.cc', + 'tcp-l4-protocol.cc', 'arp-header.cc', 'arp-cache.cc', 'arp-ipv4-interface.cc', 'arp-l3-protocol.cc', 'ipv4-loopback-interface.cc', 'udp-socket.cc', + 'tcp-socket.cc', 'ipv4-end-point-demux.cc', 'ipv4-impl.cc', 'ascii-trace.cc', 'pcap-trace.cc', 'udp-impl.cc', + 'tcp-impl.cc', + 'pending-data.cc', + 'sequence-number.cc', + 'rtt-estimator.cc', ] headers = bld.create_obj('ns3header') @@ -35,4 +42,5 @@ def build(bld): 'pcap-trace.h', 'ipv4-header.h', 'udp-header.h', + 'tcp-header.h', ] diff --git a/src/node/socket.cc b/src/node/socket.cc index d6e47e3f1..99e61b831 100644 --- a/src/node/socket.cc +++ b/src/node/socket.cc @@ -108,6 +108,12 @@ int Socket::SendTo (const Address &address, const uint8_t* buf, uint32_t size) return SendTo (address,p); } +int Socket::Listen(uint32_t queueLimit) +{ + return 0; //XXX the base class version does nothing +} + + void Socket::NotifyCloseCompleted (void) { diff --git a/src/node/socket.h b/src/node/socket.h index c27de2f59..39a45672c 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -196,6 +196,13 @@ public: */ virtual int SendTo(const Address &address,Ptr p) = 0; + /** + * \brief Listen for incoming connections. + * \param queueLimit maximum number of incoming request to queue + * \returns XXX an error code + */ + virtual int Listen(uint32_t queueLimit); + /** * \brief Send data to a specified peer. * \param address IP Address of remote host diff --git a/src/node/tcp.cc b/src/node/tcp.cc new file mode 100644 index 000000000..01346debe --- /dev/null +++ b/src/node/tcp.cc @@ -0,0 +1,71 @@ +/* -*- 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 + */ +#include "tcp.h" + +namespace ns3 { + +NumericDefaultValue Tcp::defaultSegSize +("TcpDefaultSegmentSize", +"Default TCP maximum segment size in bytes (may be adjusted based on MTU discovery)", +536); + +NumericDefaultValue Tcp::defaultAdvWin +("TcpDefaultAdvertisedWindowSize", +"Default TCP advertised window size (bytes)", +0xffff); + +NumericDefaultValue Tcp::defaultSSThresh +("TcpDefaultSlowStartThreshold", +"Default TCP slow start threshold (bytes)", +0xffff); + +NumericDefaultValue Tcp::defaultTxBuffer +("TcpDefaultTxBufferSize", +"Default TCP maximum transmit buffer size (bytes)", +0xffffffffl); + +NumericDefaultValue Tcp::defaultRxBuffer +("TcpDefaultRxBufferSize", +"Default TCP maximum receive buffer size (bytes)", +0xffffffffl); + +NumericDefaultValue Tcp::defaultInitialCWnd +("TcpDefaultInitialCongestionWindowSize", +"Default TCP initial congestion window size (segments)", +1); + +NumericDefaultValue Tcp::defaultConnTimeout +("TcpDefaultConnTimeout", +"Default TCP retransmission timeout when opening connection (seconds)", +6); + +NumericDefaultValue Tcp::defaultConnCount +("TcpDefaultConnCount", +"Default number of connection attempts (SYN retransmissions) before returning failure", +3); + +const InterfaceId Tcp::iid = MakeInterfaceId ("Tcp", SocketFactory::iid); + +Tcp::Tcp () +{ + SetInterfaceId (Tcp::iid); +} + +} // namespace ns3 diff --git a/src/node/tcp.h b/src/node/tcp.h new file mode 100644 index 000000000..1e4e4edeb --- /dev/null +++ b/src/node/tcp.h @@ -0,0 +1,67 @@ +/* -*- 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 + */ +#ifndef TCP_H +#define TCP_H + +#include "ns3/default-value.h" +#include "socket-factory.h" + +namespace ns3 { + +class Socket; + +/** + * \brief API to create TCP socket instances + * + * This abstract class defines the API for TCP sockets. + * This class also holds the global default variables used to + * initialize newly created sockets, such as values that are + * set through the sysctl or proc interfaces in Linux. + + * All TCP implementations must provide an implementation of CreateSocket + * below, and should make use of the default values configured below. + * + * \see TcpImpl + * + */ +class Tcp : public SocketFactory +{ +public: + static const InterfaceId iid; + + Tcp (); + + virtual Ptr CreateSocket (void) = 0; + +public: + static NumericDefaultValue defaultSegSize; + static NumericDefaultValue defaultAdvWin; + static NumericDefaultValue defaultSSThresh; + static NumericDefaultValue defaultTxBuffer; + static NumericDefaultValue defaultRxBuffer; + static NumericDefaultValue defaultInitialCWnd; + static NumericDefaultValue defaultConnTimeout; + static NumericDefaultValue defaultConnCount; + +}; + +} // namespace ns3 + +#endif /* UDP_H */ diff --git a/src/node/wscript b/src/node/wscript index c491b8b0e..893659fb9 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -25,6 +25,7 @@ def build(bld): 'packet-socket-factory.cc', 'packet-socket.cc', 'udp.cc', + 'tcp.cc', 'ipv4.cc', 'application.cc', ] @@ -52,6 +53,7 @@ def build(bld): 'socket-factory.h', 'packet-socket-factory.h', 'udp.h', + 'tcp.h', 'ipv4.h', 'application.h', ]