--- a/examples/tcp-large-transfer.cc Thu Jun 19 14:53:53 2008 -0700
+++ b/examples/tcp-large-transfer.cc Thu Jun 19 14:58:46 2008 -0700
@@ -25,12 +25,10 @@
// - 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
+// "tcp-large-transfer-$n-$i.pcap" where n and i represent node and interface
+// numbers respectively
// Usage (e.g.): ./waf --run tcp-large-transfer
-//XXX this isn't working as described right now
-//it is just blasting away for 10 seconds, with no fixed amount of data
-//being sent
#include <ctype.h>
#include <iostream>
@@ -48,37 +46,15 @@
NS_LOG_COMPONENT_DEFINE ("TcpLargeTransfer");
-void
-ApplicationTraceSink (Ptr<const Packet> packet,
- const Address &addr)
-{
-// g_log is not declared in optimized builds
-// should convert this to use of some other flag than the logging system
-#ifdef NS3_LOG_ENABLE
- 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;
- }
- }
-#endif
-}
+// The number of bytes to send in this simulation.
+static uint32_t txBytes = 2000000;
-void CloseConnection (Ptr<Socket> localSocket);
-void StartFlow(Ptr<Socket>, uint32_t, Ipv4Address, uint16_t);
+// These are for starting the writing process, and handling the sending
+// socket's notification upcalls (events). These two together more or less
+// implement a sending "Application", although not a proper ns3::Application
+// subclass.
+
+void StartFlow(Ptr<Socket>, Ipv4Address, uint16_t);
void WriteUntilBufferFull (Ptr<Socket>, uint32_t);
int main (int argc, char *argv[])
@@ -101,27 +77,34 @@
CommandLine cmd;
cmd.Parse (argc, argv);
- // Here, we will explicitly create three nodes.
- NodeContainer c0;
- c0.Create (2);
+ // Here, we will explicitly create three nodes. The first container contains
+ // nodes 0 and 1 from the diagram above, and the second one contains nodes
+ // 1 and 2. This reflects the channel connectivity, and will be used to
+ // install the network interfaces and connect them with a channel.
+ NodeContainer n0n1;
+ n0n1.Create (2);
- NodeContainer c1;
- c1.Add (c0.Get (1));
- c1.Create (1);
+ NodeContainer n1n2;
+ n1n2.Add (n0n1.Get (1));
+ n1n2.Create (1);
// We create the channels first without any IP addressing information
+ // First make and configure the helper, so that it will put the appropriate
+ // parameters on the network interfaces and channels we are about to install.
PointToPointHelper p2p;
p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate(10000000)));
p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds(10)));
- NetDeviceContainer dev0 = p2p.Install (c0);
- NetDeviceContainer dev1 = p2p.Install (c1);
+
+ // And then install devices and channels connecting our topology.
+ NetDeviceContainer dev0 = p2p.Install (n0n1);
+ NetDeviceContainer dev1 = p2p.Install (n1n2);
- // add ip/tcp stack to nodes.
- NodeContainer c = NodeContainer (c0, c1.Get (1));
+ // Now add ip/tcp stack to all nodes.
+ NodeContainer allNodes = NodeContainer (n0n1, n1n2.Get (1));
InternetStackHelper internet;
- internet.Install (c);
+ internet.Install (allNodes);
- // Later, we add IP addresses.
+ // Later, we add IP addresses.
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
ipv4.Assign (dev0);
@@ -133,82 +116,105 @@
///////////////////////////////////////////////////////////////////////////
// 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
+ // Should observe SYN exchange, a lot of data segments and ACKS, and FIN
+ // exchange. FIN exchange isn't quite compliant with TCP spec (see release
+ // notes for more info)
//
///////////////////////////////////////////////////////////////////////////
- int nBytes = 2000000;
uint16_t servPort = 50000;
- // Create a packet sink to receive these packets
+ // Create a packet sink to receive these packets on n2...
PacketSinkHelper sink ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny (), servPort));
- ApplicationContainer apps = sink.Install (c1.Get (1));
+ ApplicationContainer apps = sink.Install (n1n2.Get (1));
apps.Start (Seconds (0.0));
- // and generate traffic to remote sink.
- //TypeId tid = TypeId::LookupByName ("ns3::TcpSocketFactory");
- Ptr<Socket> localSocket = Socket::CreateSocket (c0.Get (0), TcpSocketFactory::GetTypeId ());
+ // Create a source to send packets from n0. Instead of a full Application
+ // and the helper APIs you might see in other example files, this example
+ // will use sockets directly and register some socket callbacks as a sending
+ // "Application".
+
+ // Create and bind the socket...
+ Ptr<Socket> localSocket =
+ Socket::CreateSocket (n0n1.Get (0), TcpSocketFactory::GetTypeId ());
localSocket->Bind ();
- Simulator::ScheduleNow (&StartFlow, localSocket, nBytes,
+
+ // ...and schedule the sending "Application"; This is similar to what an
+ // ns3::Application subclass would do internally.
+ Simulator::ScheduleNow (&StartFlow, localSocket,
ipInterfs.GetAddress (1), servPort);
- Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/Rx",
- MakeCallback (&ApplicationTraceSink));
+ // One can toggle the comment for the following line on or off to see the
+ // effects of finite send buffer modelling. One can also change the size of
+ // said buffer.
+ //localSocket->SetAttribute("SndBufSize", UintegerValue(4096));
+
+ //Ask for ASCII and pcap traces of network traffic
std::ofstream ascii;
ascii.open ("tcp-large-transfer.tr");
PointToPointHelper::EnableAsciiAll (ascii);
PointToPointHelper::EnablePcapAll ("tcp-large-transfer");
+ // Finally, set up the simulator to run. The 1000 second hard limit is a
+ // failsafe in case some change above causes the simulation to never end
Simulator::Stop (Seconds(1000));
Simulator::Run ();
Simulator::Destroy ();
}
-void CloseConnection (Ptr<Socket> localSocket)
-{
- localSocket->Close ();
-}
-void StartFlow(Ptr<Socket> localSocket, uint32_t nBytes,
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//begin implementation of sending "Application"
+void StartFlow(Ptr<Socket> localSocket,
Ipv4Address servAddress,
uint16_t servPort)
{
- // NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ());
+ NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ());
localSocket->Connect (InetSocketAddress (servAddress, servPort));//connect
- localSocket->SetConnectCallback (MakeCallback (&CloseConnection),
- Callback<void, Ptr<Socket> > ());
- //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
+
+ // tell the tcp implementation to call WriteUntilBufferFull again
+ // if we blocked and new tx buffer space becomes available
localSocket->SetSendCallback (MakeCallback (&WriteUntilBufferFull));
- WriteUntilBufferFull (localSocket, nBytes);
+ WriteUntilBufferFull (localSocket, txBytes);
}
-void WriteUntilBufferFull (Ptr<Socket> localSocket, uint32_t nBytes)
+void WriteUntilBufferFull (Ptr<Socket> localSocket, uint32_t txSpace)
{
// 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;
+
+ while (txBytes > 0) {
+ uint32_t curSize= txBytes > writeSize ? writeSize : txBytes;
+ if (curSize > txSpace)
+ curSize = txSpace;
for(uint32_t i = 0; i < curSize; ++i)
{
char m = toascii (97 + i % 26);
data[i] = m;
}
- uint32_t amountSent = localSocket->Send (data, curSize, 0);
- if(amountSent < curSize)
+ int amountSent = localSocket->Send (data, curSize, 0);
+ if(amountSent < 0)
{
- std::cout << "Socket blocking, returning" << std::endl;
+ // we will be called again when new tx space becomes available.
+ std::cout << "Socket blocking, " << txBytes << " left to write, returning" << std::endl;
return;
}
- nBytes -= curSize;
+ txBytes -= curSize;
+ if (amountSent != (int)curSize)
+ {
+ std::cout << "Short Write, returning" << std::endl;
+ return;
+ }
}
+ localSocket->Close ();
}