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