|
|
|
1 |
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
2 |
/* |
3 |
* Copyright 2007 University of Washington |
4 |
* |
5 |
* This program is free software; you can redistribute it and/or modify |
6 |
* it under the terms of the GNU General Public License version 2 as |
7 |
* published by the Free Software Foundation; |
8 |
* |
9 |
* This program is distributed in the hope that it will be useful, |
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
* GNU General Public License for more details. |
13 |
* |
14 |
* You should have received a copy of the GNU General Public License |
15 |
* along with this program; if not, write to the Free Software |
16 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
17 |
*/ |
18 |
#include "ns3/log.h" |
19 |
#include "ns3/ipv4-address.h" |
20 |
#include "ns3/nstime.h" |
21 |
#include "ns3/inet-socket-address.h" |
22 |
#include "ns3/socket.h" |
23 |
#include "ns3/simulator.h" |
24 |
#include "ns3/socket-factory.h" |
25 |
#include "ns3/packet.h" |
26 |
#include "ns3/uinteger.h" |
27 |
#include "ns3/trace-source-accessor.h" |
28 |
#include "tcp-echo-client.h" |
29 |
|
30 |
namespace ns3 { |
31 |
|
32 |
NS_LOG_COMPONENT_DEFINE ("TcpEchoClientApplication"); |
33 |
NS_OBJECT_ENSURE_REGISTERED (TcpEchoClient); |
34 |
|
35 |
TypeId |
36 |
TcpEchoClient::GetTypeId (void) |
37 |
{ |
38 |
static TypeId tid = TypeId ("ns3::TcpEchoClient") |
39 |
.SetParent<Application> () |
40 |
.AddConstructor<TcpEchoClient> () |
41 |
.AddAttribute ("MaxPackets", |
42 |
"The maximum number of packets the application will send", |
43 |
UintegerValue (100), |
44 |
MakeUintegerAccessor (&TcpEchoClient::m_count), |
45 |
MakeUintegerChecker<uint32_t> ()) |
46 |
.AddAttribute ("Interval", |
47 |
"The time to wait between packets", |
48 |
TimeValue (Seconds (1.0)), |
49 |
MakeTimeAccessor (&TcpEchoClient::m_interval), |
50 |
MakeTimeChecker ()) |
51 |
.AddAttribute ("RemoteAddress", |
52 |
"The destination Ipv4Address of the outbound packets", |
53 |
Ipv4AddressValue (), |
54 |
MakeIpv4AddressAccessor (&TcpEchoClient::m_peerAddress), |
55 |
MakeIpv4AddressChecker ()) |
56 |
.AddAttribute ("RemotePort", |
57 |
"The destination port of the outbound packets", |
58 |
UintegerValue (0), |
59 |
MakeUintegerAccessor (&TcpEchoClient::m_peerPort), |
60 |
MakeUintegerChecker<uint16_t> ()) |
61 |
.AddAttribute ("PacketSize", "Size of echo data in outbound packets", |
62 |
UintegerValue (100), |
63 |
MakeUintegerAccessor (&TcpEchoClient::SetDataSize, |
64 |
&TcpEchoClient::GetDataSize), |
65 |
MakeUintegerChecker<uint32_t> ()) |
66 |
.AddTraceSource ("Tx", "A new packet is created and is sent", |
67 |
MakeTraceSourceAccessor (&TcpEchoClient::m_txTrace)) |
68 |
; |
69 |
return tid; |
70 |
} |
71 |
|
72 |
TcpEchoClient::TcpEchoClient () |
73 |
{ |
74 |
NS_LOG_FUNCTION_NOARGS (); |
75 |
m_sent = 0; |
76 |
m_bytesSent = 0; |
77 |
m_recvBack = 0; |
78 |
m_bytesRecvBack = 0; |
79 |
m_socket = 0; |
80 |
m_sendEvent = EventId (); |
81 |
m_data = 0; |
82 |
m_dataSize = 0; |
83 |
} |
84 |
|
85 |
TcpEchoClient::~TcpEchoClient() |
86 |
{ |
87 |
NS_LOG_FUNCTION_NOARGS (); |
88 |
m_socket = 0; |
89 |
|
90 |
delete [] m_data; |
91 |
m_data = 0; |
92 |
m_dataSize = 0; |
93 |
} |
94 |
|
95 |
void |
96 |
TcpEchoClient::SetRemote (Ipv4Address ip, uint16_t port) |
97 |
{ |
98 |
m_peerAddress = ip; |
99 |
m_peerPort = port; |
100 |
} |
101 |
|
102 |
void |
103 |
TcpEchoClient::DoDispose (void) |
104 |
{ |
105 |
NS_LOG_FUNCTION_NOARGS (); |
106 |
Application::DoDispose (); |
107 |
} |
108 |
|
109 |
void |
110 |
TcpEchoClient::StartApplication (void) |
111 |
{ |
112 |
NS_LOG_FUNCTION_NOARGS (); |
113 |
|
114 |
if (m_socket == 0) |
115 |
{ |
116 |
TypeId tid = TypeId::LookupByName ("ns3::TcpSocketFactory"); |
117 |
m_socket = Socket::CreateSocket (GetNode (), tid); |
118 |
m_socket->Bind (); |
119 |
m_socket->Connect (InetSocketAddress (m_peerAddress, m_peerPort)); |
120 |
} |
121 |
|
122 |
m_socket->SetRecvCallback (MakeCallback (&TcpEchoClient::ReceivePacket, this)); |
123 |
|
124 |
ScheduleTransmit (Seconds (0.)); |
125 |
} |
126 |
|
127 |
void |
128 |
TcpEchoClient::StopApplication () |
129 |
{ |
130 |
NS_LOG_FUNCTION_NOARGS (); |
131 |
|
132 |
if (m_socket != 0) |
133 |
{ |
134 |
m_socket->Close (); |
135 |
m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ()); |
136 |
m_socket = 0; |
137 |
} |
138 |
|
139 |
Simulator::Cancel (m_sendEvent); |
140 |
} |
141 |
|
142 |
void |
143 |
TcpEchoClient::SetDataSize (uint32_t dataSize) |
144 |
{ |
145 |
NS_LOG_FUNCTION (dataSize); |
146 |
|
147 |
// |
148 |
// If the client is setting the echo packet data size this way, we infer |
149 |
// that she doesn't care about the contents of the packet at all, so |
150 |
// neither will we. |
151 |
// |
152 |
delete [] m_data; |
153 |
m_data = 0; |
154 |
m_dataSize = 0; |
155 |
m_size = dataSize; |
156 |
} |
157 |
|
158 |
uint32_t |
159 |
TcpEchoClient::GetDataSize (void) const |
160 |
{ |
161 |
NS_LOG_FUNCTION_NOARGS (); |
162 |
return m_size; |
163 |
} |
164 |
|
165 |
void |
166 |
TcpEchoClient::SetFill (std::string fill) |
167 |
{ |
168 |
NS_LOG_FUNCTION (fill); |
169 |
|
170 |
uint32_t dataSize = fill.size () + 1; |
171 |
|
172 |
if (dataSize != m_dataSize) |
173 |
{ |
174 |
delete [] m_data; |
175 |
m_data = new uint8_t [dataSize]; |
176 |
m_dataSize = dataSize; |
177 |
} |
178 |
|
179 |
memcpy (m_data, fill.c_str (), dataSize); |
180 |
|
181 |
// |
182 |
// Overwrite packet size attribute. |
183 |
// |
184 |
m_size = dataSize; |
185 |
} |
186 |
|
187 |
void |
188 |
TcpEchoClient::SetFill (uint8_t fill, uint32_t dataSize) |
189 |
{ |
190 |
if (dataSize != m_dataSize) |
191 |
{ |
192 |
delete [] m_data; |
193 |
m_data = new uint8_t [dataSize]; |
194 |
m_dataSize = dataSize; |
195 |
} |
196 |
|
197 |
memset (m_data, fill, dataSize); |
198 |
|
199 |
// |
200 |
// Overwrite packet size attribute. |
201 |
// |
202 |
m_size = dataSize; |
203 |
} |
204 |
|
205 |
void |
206 |
TcpEchoClient::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize) |
207 |
{ |
208 |
if (dataSize != m_dataSize) |
209 |
{ |
210 |
delete [] m_data; |
211 |
m_data = new uint8_t [dataSize]; |
212 |
m_dataSize = dataSize; |
213 |
} |
214 |
|
215 |
if (fillSize >= dataSize) |
216 |
{ |
217 |
memcpy (m_data, fill, dataSize); |
218 |
return; |
219 |
} |
220 |
|
221 |
// |
222 |
// Do all but the final fill. |
223 |
// |
224 |
uint32_t filled = 0; |
225 |
while (filled + fillSize < dataSize) |
226 |
{ |
227 |
memcpy (&m_data[filled], fill, fillSize); |
228 |
filled += fillSize; |
229 |
} |
230 |
|
231 |
// |
232 |
// Last fill may be partial |
233 |
// |
234 |
memcpy (&m_data[filled], fill, dataSize - filled); |
235 |
|
236 |
// |
237 |
// Overwrite packet size attribute. |
238 |
// |
239 |
m_size = dataSize; |
240 |
} |
241 |
|
242 |
void |
243 |
TcpEchoClient::ScheduleTransmit (Time dt) |
244 |
{ |
245 |
NS_LOG_FUNCTION_NOARGS (); |
246 |
m_sendEvent = Simulator::Schedule (dt, &TcpEchoClient::Send, this); |
247 |
} |
248 |
|
249 |
void |
250 |
TcpEchoClient::Send (void) |
251 |
{ |
252 |
NS_LOG_FUNCTION_NOARGS (); |
253 |
|
254 |
NS_ASSERT (m_sendEvent.IsExpired ()); |
255 |
|
256 |
Ptr<Packet> p; |
257 |
if (m_dataSize) |
258 |
{ |
259 |
// |
260 |
// If m_dataSize is non-zero, we have a data buffer of the same size that we |
261 |
// are expected to copy and send. This state of affairs is created if one of |
262 |
// the Fill functions is called. In this case, m_size must have been set |
263 |
// to agree with m_dataSize |
264 |
// |
265 |
NS_ASSERT_MSG (m_dataSize == m_size, "TcpEchoClient::Send(): m_size and m_dataSize inconsistent"); |
266 |
NS_ASSERT_MSG (m_data, "TcpEchoClient::Send(): m_dataSize but no m_data"); |
267 |
p = Create<Packet> (m_data, m_dataSize); |
268 |
m_bytesSent += m_dataSize; |
269 |
} |
270 |
else |
271 |
{ |
272 |
// |
273 |
// If m_dataSize is zero, the client has indicated that she doesn't care |
274 |
// about the data itself either by specifying the data size by setting |
275 |
// the corresponding atribute or by not calling a SetFill function. In |
276 |
// this case, we don't worry about it either. But we do allow m_size |
277 |
// to have a value different from the (zero) m_dataSize. |
278 |
// |
279 |
p = Create<Packet> (m_size); |
280 |
m_bytesSent += m_size; |
281 |
} |
282 |
// call to the trace sinks before the packet is actually sent, |
283 |
// so that tags added to the packet can be sent as well |
284 |
m_txTrace (p); |
285 |
m_socket->Send (p); |
286 |
|
287 |
++m_sent; |
288 |
|
289 |
NS_LOG_INFO ("Sent " << m_size << " bytes to " << m_peerAddress); |
290 |
|
291 |
if (m_sent < m_count) |
292 |
{ |
293 |
ScheduleTransmit (m_interval); |
294 |
} |
295 |
} |
296 |
|
297 |
void |
298 |
TcpEchoClient::ReceivePacket (Ptr<Socket> socket) |
299 |
{ |
300 |
NS_LOG_FUNCTION (this << socket); |
301 |
Ptr<Packet> packet; |
302 |
Address from; |
303 |
while (packet = socket->RecvFrom (from)) |
304 |
{ |
305 |
NS_LOG_INFO ("Received " << packet->GetSize () << " bytes from " << |
306 |
InetSocketAddress::ConvertFrom (from).GetIpv4 ()); |
307 |
|
308 |
// dont check if data returned is the same data sent earlier |
309 |
m_recvBack++; |
310 |
m_bytesRecvBack += packet->GetSize (); |
311 |
} |
312 |
|
313 |
if (m_count == m_recvBack) |
314 |
{ |
315 |
socket->Close(); |
316 |
m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ()); |
317 |
socket = 0; |
318 |
} |
319 |
} |
320 |
|
321 |
} // Namespace ns3 |