1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 as
5  * published by the Free Software Foundation;
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16 
17 #include <fstream>
18 #include "ns3/core-module.h"
19 #include "ns3/network-module.h"
20 #include "ns3/internet-module.h"
21 #include "ns3/point-to-point-module.h"
22 #include "ns3/applications-module.h"
23 
24 using namespace ns3;
25 
26 NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");
27 
28 // ===========================================================================
29 //
30 //         node 0                 node 1
31 //   +----------------+    +----------------+
32 //   |    ns-3 TCP    |    |    ns-3 TCP    |
33 //   +----------------+    +----------------+
34 //   |    10.1.1.1    |    |    10.1.1.2    |
35 //   +----------------+    +----------------+
36 //   | point-to-point |    | point-to-point |
37 //   +----------------+    +----------------+
38 //           |                     |
39 //           +---------------------+
40 //                5 Mbps, 2 ms
41 //
42 //
43 // We want to look at changes in the ns-3 TCP congestion window.  We need
44 // to crank up a flow and hook the CongestionWindow attribute on the socket
45 // of the sender.  Normally one would use an on-off application to generate a
46 // flow, but this has a couple of problems.  First, the socket of the on-off
47 // application is not created until Application Start time, so we wouldn't be
48 // able to hook the socket (now) at configuration time.  Second, even if we
49 // could arrange a call after start time, the socket is not public so we
50 // couldn't get at it.
51 //
52 // So, we can cook up a simple version of the on-off application that does what
53 // we want.  On the plus side we don't need all of the complexity of the on-off
54 // application.  On the minus side, we don't have a helper, so we have to get
55 // a little more involved in the details, but this is trivial.
56 //
57 // So first, we create a socket and do the trace connect on it; then we pass
58 // this socket into the constructor of our simple application which we then
59 // install in the source node.
60 // ===========================================================================
61 //
62 class MyApp : public Application
63 {
64 public:
65 
66   MyApp ();
67   virtual ~MyApp();
68 
69   void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);
70 
71 private:
72   virtual void StartApplication (void);
73   virtual void StopApplication (void);
74 
75   void ScheduleTx (void);
76   void SendPacket (void);
77 
78   Ptr<Socket>     m_socket;
79   Address         m_peer;
80   uint32_t        m_packetSize;
81   uint32_t        m_nPackets;
82   DataRate        m_dataRate;
83   EventId         m_sendEvent;
84   bool            m_running;
85   uint32_t        m_packetsSent;
86 };
87 
MyApp()88 MyApp::MyApp ()
89   : m_socket (0),
90     m_peer (),
91     m_packetSize (0),
92     m_nPackets (0),
93     m_dataRate (0),
94     m_sendEvent (),
95     m_running (false),
96     m_packetsSent (0)
97 {
98 }
99 
~MyApp()100 MyApp::~MyApp()
101 {
102   m_socket = 0;
103 }
104 
105 void
Setup(Ptr<Socket> socket,Address address,uint32_t packetSize,uint32_t nPackets,DataRate dataRate)106 MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
107 {
108   m_socket = socket;
109   m_peer = address;
110   m_packetSize = packetSize;
111   m_nPackets = nPackets;
112   m_dataRate = dataRate;
113 }
114 
115 void
StartApplication(void)116 MyApp::StartApplication (void)
117 {
118   m_running = true;
119   m_packetsSent = 0;
120   m_socket->Bind ();
121   m_socket->Connect (m_peer);
122   SendPacket ();
123 }
124 
125 void
StopApplication(void)126 MyApp::StopApplication (void)
127 {
128   m_running = false;
129 
130   if (m_sendEvent.IsRunning ())
131     {
132       Simulator::Cancel (m_sendEvent);
133     }
134 
135   if (m_socket)
136     {
137       m_socket->Close ();
138     }
139 }
140 
141 void
SendPacket(void)142 MyApp::SendPacket (void)
143 {
144   Ptr<Packet> packet = Create<Packet> (m_packetSize);
145   m_socket->Send (packet);
146 
147   if (++m_packetsSent < m_nPackets)
148     {
149       ScheduleTx ();
150     }
151 }
152 
153 void
ScheduleTx(void)154 MyApp::ScheduleTx (void)
155 {
156   if (m_running)
157     {
158       Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
159       m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
160     }
161 }
162 
163 static void
CwndChange(uint32_t oldCwnd,uint32_t newCwnd)164 CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
165 {
166   NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
167 }
168 
169 static void
RxDrop(Ptr<const Packet> p)170 RxDrop (Ptr<const Packet> p)
171 {
172   NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
173 }
174 
175 int
main(int argc,char * argv[])176 main (int argc, char *argv[])
177 {
178   CommandLine cmd (__FILE__);
179   cmd.Parse (argc, argv);
180 
181   NodeContainer nodes;
182   nodes.Create (2);
183 
184   PointToPointHelper pointToPoint;
185   pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
186   pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
187 
188   NetDeviceContainer devices;
189   devices = pointToPoint.Install (nodes);
190 
191   Ptr<RateErrorModel> em = CreateObject<RateErrorModel> ();
192   em->SetAttribute ("ErrorRate", DoubleValue (0.00001));
193   devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
194 
195   InternetStackHelper stack;
196   stack.Install (nodes);
197 
198   Ipv4AddressHelper address;
199   address.SetBase ("10.1.1.0", "255.255.255.252");
200   Ipv4InterfaceContainer interfaces = address.Assign (devices);
201 
202   uint16_t sinkPort = 8080;
203   Address sinkAddress (InetSocketAddress (interfaces.GetAddress (1), sinkPort));
204   PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
205   ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
206   sinkApps.Start (Seconds (0.));
207   sinkApps.Stop (Seconds (20.));
208 
209   Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ());
210   ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndChange));
211 
212   Ptr<MyApp> app = CreateObject<MyApp> ();
213   app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
214   nodes.Get (0)->AddApplication (app);
215   app->SetStartTime (Seconds (1.));
216   app->SetStopTime (Seconds (20.));
217 
218   devices.Get (1)->TraceConnectWithoutContext ("PhyRxDrop", MakeCallback (&RxDrop));
219 
220   Simulator::Stop (Seconds (20));
221   Simulator::Run ();
222   Simulator::Destroy ();
223 
224   return 0;
225 }
226 
227