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