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 ("SixthScriptExample");
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   MyApp ();
66   virtual ~MyApp ();
67 
68   /**
69    * Register this type.
70    * \return The TypeId.
71    */
72   static TypeId GetTypeId (void);
73   void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);
74 
75 private:
76   virtual void StartApplication (void);
77   virtual void StopApplication (void);
78 
79   void ScheduleTx (void);
80   void SendPacket (void);
81 
82   Ptr<Socket>     m_socket;
83   Address         m_peer;
84   uint32_t        m_packetSize;
85   uint32_t        m_nPackets;
86   DataRate        m_dataRate;
87   EventId         m_sendEvent;
88   bool            m_running;
89   uint32_t        m_packetsSent;
90 };
91 
MyApp()92 MyApp::MyApp ()
93   : m_socket (0),
94     m_peer (),
95     m_packetSize (0),
96     m_nPackets (0),
97     m_dataRate (0),
98     m_sendEvent (),
99     m_running (false),
100     m_packetsSent (0)
101 {
102 }
103 
~MyApp()104 MyApp::~MyApp ()
105 {
106   m_socket = 0;
107 }
108 
109 /* static */
GetTypeId(void)110 TypeId MyApp::GetTypeId (void)
111 {
112   static TypeId tid = TypeId ("MyApp")
113     .SetParent<Application> ()
114     .SetGroupName ("Tutorial")
115     .AddConstructor<MyApp> ()
116     ;
117   return tid;
118 }
119 
120 void
Setup(Ptr<Socket> socket,Address address,uint32_t packetSize,uint32_t nPackets,DataRate dataRate)121 MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
122 {
123   m_socket = socket;
124   m_peer = address;
125   m_packetSize = packetSize;
126   m_nPackets = nPackets;
127   m_dataRate = dataRate;
128 }
129 
130 void
StartApplication(void)131 MyApp::StartApplication (void)
132 {
133   m_running = true;
134   m_packetsSent = 0;
135   m_socket->Bind ();
136   m_socket->Connect (m_peer);
137   SendPacket ();
138 }
139 
140 void
StopApplication(void)141 MyApp::StopApplication (void)
142 {
143   m_running = false;
144 
145   if (m_sendEvent.IsRunning ())
146     {
147       Simulator::Cancel (m_sendEvent);
148     }
149 
150   if (m_socket)
151     {
152       m_socket->Close ();
153     }
154 }
155 
156 void
SendPacket(void)157 MyApp::SendPacket (void)
158 {
159   Ptr<Packet> packet = Create<Packet> (m_packetSize);
160   m_socket->Send (packet);
161 
162   if (++m_packetsSent < m_nPackets)
163     {
164       ScheduleTx ();
165     }
166 }
167 
168 void
ScheduleTx(void)169 MyApp::ScheduleTx (void)
170 {
171   if (m_running)
172     {
173       Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
174       m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
175     }
176 }
177 
178 static void
CwndChange(Ptr<OutputStreamWrapper> stream,uint32_t oldCwnd,uint32_t newCwnd)179 CwndChange (Ptr<OutputStreamWrapper> stream, uint32_t oldCwnd, uint32_t newCwnd)
180 {
181   NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
182   *stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
183 }
184 
185 static void
RxDrop(Ptr<PcapFileWrapper> file,Ptr<const Packet> p)186 RxDrop (Ptr<PcapFileWrapper> file, Ptr<const Packet> p)
187 {
188   NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
189   file->Write (Simulator::Now (), p);
190 }
191 
192 int
main(int argc,char * argv[])193 main (int argc, char *argv[])
194 {
195   CommandLine cmd (__FILE__);
196   cmd.Parse (argc, argv);
197 
198   NodeContainer nodes;
199   nodes.Create (2);
200 
201   PointToPointHelper pointToPoint;
202   pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
203   pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
204 
205   NetDeviceContainer devices;
206   devices = pointToPoint.Install (nodes);
207 
208   Ptr<RateErrorModel> em = CreateObject<RateErrorModel> ();
209   em->SetAttribute ("ErrorRate", DoubleValue (0.00001));
210   devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
211 
212   InternetStackHelper stack;
213   stack.Install (nodes);
214 
215   Ipv4AddressHelper address;
216   address.SetBase ("10.1.1.0", "255.255.255.252");
217   Ipv4InterfaceContainer interfaces = address.Assign (devices);
218 
219   uint16_t sinkPort = 8080;
220   Address sinkAddress (InetSocketAddress (interfaces.GetAddress (1), sinkPort));
221   PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
222   ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
223   sinkApps.Start (Seconds (0.));
224   sinkApps.Stop (Seconds (20.));
225 
226   Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ());
227 
228   Ptr<MyApp> app = CreateObject<MyApp> ();
229   app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
230   nodes.Get (0)->AddApplication (app);
231   app->SetStartTime (Seconds (1.));
232   app->SetStopTime (Seconds (20.));
233 
234   AsciiTraceHelper asciiTraceHelper;
235   Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd");
236   ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));
237 
238   PcapHelper pcapHelper;
239   Ptr<PcapFileWrapper> file = pcapHelper.CreateFile ("sixth.pcap", std::ios::out, PcapHelper::DLT_PPP);
240   devices.Get (1)->TraceConnectWithoutContext ("PhyRxDrop", MakeBoundCallback (&RxDrop, file));
241 
242   Simulator::Stop (Seconds (20));
243   Simulator::Run ();
244   Simulator::Destroy ();
245 
246   return 0;
247 }
248 
249