A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
v4ping.cc
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 #include "v4ping.h"
17 #include "ns3/icmpv4.h"
18 #include "ns3/assert.h"
19 #include "ns3/log.h"
20 #include "ns3/ipv4-address.h"
21 #include "ns3/socket.h"
22 #include "ns3/uinteger.h"
23 #include "ns3/boolean.h"
24 #include "ns3/inet-socket-address.h"
25 #include "ns3/packet.h"
26 #include "ns3/trace-source-accessor.h"
27 
28 namespace ns3 {
29 
30 NS_LOG_COMPONENT_DEFINE ("V4Ping");
31 NS_OBJECT_ENSURE_REGISTERED (V4Ping);
32 
33 TypeId
34 V4Ping::GetTypeId (void)
35 {
36  static TypeId tid = TypeId ("ns3::V4Ping")
37  .SetParent<Application> ()
38  .AddConstructor<V4Ping> ()
39  .AddAttribute ("Remote",
40  "The address of the machine we want to ping.",
41  Ipv4AddressValue (),
42  MakeIpv4AddressAccessor (&V4Ping::m_remote),
43  MakeIpv4AddressChecker ())
44  .AddAttribute ("Verbose",
45  "Produce usual output.",
46  BooleanValue (false),
47  MakeBooleanAccessor (&V4Ping::m_verbose),
48  MakeBooleanChecker ())
49  .AddAttribute ("Interval", "Wait interval seconds between sending each packet.",
50  TimeValue (Seconds (1)),
51  MakeTimeAccessor (&V4Ping::m_interval),
52  MakeTimeChecker ())
53  .AddAttribute ("Size", "The number of data bytes to be sent, real packet will be 8 (ICMP) + 20 (IP) bytes longer.",
54  UintegerValue (56),
55  MakeUintegerAccessor (&V4Ping::m_size),
56  MakeUintegerChecker<uint32_t> (16))
57  .AddTraceSource ("Rtt",
58  "The rtt calculated by the ping.",
59  MakeTraceSourceAccessor (&V4Ping::m_traceRtt));
60  ;
61  return tid;
62 }
63 
65  : m_interval (Seconds (1)),
66  m_size (56),
67  m_socket (0),
68  m_seq (0),
69  m_verbose (false),
70  m_recv (0)
71 {
72  NS_LOG_FUNCTION (this);
73 }
74 V4Ping::~V4Ping ()
75 {
76  NS_LOG_FUNCTION (this);
77 }
78 
79 void
81 {
82  NS_LOG_FUNCTION (this);
83  m_socket = 0;
85 }
86 
87 uint32_t
88 V4Ping::GetApplicationId (void) const
89 {
90  NS_LOG_FUNCTION (this);
91  Ptr<Node> node = GetNode ();
92  for (uint32_t i = 0; i < node->GetNApplications (); ++i)
93  {
94  if (node->GetApplication (i) == this)
95  {
96  return i;
97  }
98  }
99  NS_ASSERT_MSG (false, "forgot to add application to node");
100  return 0; // quiet compiler
101 }
102 
103 void
104 V4Ping::Receive (Ptr<Socket> socket)
105 {
106  NS_LOG_FUNCTION (this << socket);
107  while (m_socket->GetRxAvailable () > 0)
108  {
109  Address from;
110  Ptr<Packet> p = m_socket->RecvFrom (0xffffffff, 0, from);
111  NS_LOG_DEBUG ("recv " << p->GetSize () << " bytes");
113  InetSocketAddress realFrom = InetSocketAddress::ConvertFrom (from);
114  NS_ASSERT (realFrom.GetPort () == 1); // protocol should be icmp.
115  Ipv4Header ipv4;
116  p->RemoveHeader (ipv4);
117  uint32_t recvSize = p->GetSize ();
118  NS_ASSERT (ipv4.GetProtocol () == 1); // protocol should be icmp.
119  Icmpv4Header icmp;
120  p->RemoveHeader (icmp);
121  if (icmp.GetType () == Icmpv4Header::ECHO_REPLY)
122  {
123  Icmpv4Echo echo;
124  p->RemoveHeader (echo);
125  std::map<uint16_t, Time>::iterator i = m_sent.find (echo.GetSequenceNumber ());
126 
127  if (i != m_sent.end () && echo.GetIdentifier () == 0)
128  {
129  uint32_t * buf = new uint32_t [m_size];
130  uint32_t dataSize = echo.GetDataSize ();
131  uint32_t nodeId;
132  uint32_t appId;
133  if (dataSize == m_size)
134  {
135  echo.GetData ((uint8_t *)buf);
136  Read32 ((const uint8_t *) &buf[0], nodeId);
137  Read32 ((const uint8_t *) &buf[1], appId);
138 
139  if (nodeId == GetNode ()->GetId () &&
140  appId == GetApplicationId ())
141  {
142  Time sendTime = i->second;
143  NS_ASSERT (Simulator::Now () >= sendTime);
144  Time delta = Simulator::Now () - sendTime;
145 
146  m_sent.erase (i);
147  m_avgRtt.Update (delta.GetMilliSeconds ());
148  m_recv++;
149  m_traceRtt (delta);
150 
151  if (m_verbose)
152  {
153  std::cout << recvSize << " bytes from " << realFrom.GetIpv4 () << ":"
154  << " icmp_seq=" << echo.GetSequenceNumber ()
155  << " ttl=" << (unsigned)ipv4.GetTtl ()
156  << " time=" << delta.GetMilliSeconds () << " ms\n";
157  }
158  }
159  }
160  delete[] buf;
161  }
162  }
163  }
164 }
165 
166 // Writes data to buffer in little-endian format; least significant byte
167 // of data is at lowest buffer address
168 void
169 V4Ping::Write32 (uint8_t *buffer, const uint32_t data)
170 {
171  NS_LOG_FUNCTION (this << buffer << data);
172  buffer[0] = (data >> 0) & 0xff;
173  buffer[1] = (data >> 8) & 0xff;
174  buffer[2] = (data >> 16) & 0xff;
175  buffer[3] = (data >> 24) & 0xff;
176 }
177 
178 // Writes data from a little-endian formatted buffer to data
179 void
180 V4Ping::Read32 (const uint8_t *buffer, uint32_t &data)
181 {
182  NS_LOG_FUNCTION (this << buffer << data);
183  data = (buffer[3] << 24) + (buffer[2] << 16) + (buffer[1] << 8) + buffer[0];
184 }
185 
186 void
187 V4Ping::Send ()
188 {
189  NS_LOG_FUNCTION (this);
190 
191  NS_LOG_INFO ("m_seq=" << m_seq);
192  Ptr<Packet> p = Create<Packet> ();
193  Icmpv4Echo echo;
194  echo.SetSequenceNumber (m_seq);
195  m_seq++;
196  echo.SetIdentifier (0);
197 
198  //
199  // We must write quantities out in some form of network order. Since there
200  // isn't an htonl to work with we just follow the convention in pcap traces
201  // (where any difference would show up anyway) and borrow that code. Don't
202  // be too surprised when you see that this is a little endian convention.
203  //
204  uint8_t* data = new uint8_t[m_size];
205  for (uint32_t i = 0; i < m_size; ++i) data[i] = 0;
206  NS_ASSERT (m_size >= 16);
207 
208  uint32_t tmp = GetNode ()->GetId ();
209  Write32 (&data[0 * sizeof(uint32_t)], tmp);
210 
211  tmp = GetApplicationId ();
212  Write32 (&data[1 * sizeof(uint32_t)], tmp);
213 
214  Ptr<Packet> dataPacket = Create<Packet> ((uint8_t *) data, m_size);
215  echo.SetData (dataPacket);
216  p->AddHeader (echo);
217  Icmpv4Header header;
218  header.SetType (Icmpv4Header::ECHO);
219  header.SetCode (0);
220  if (Node::ChecksumEnabled ())
221  {
222  header.EnableChecksum ();
223  }
224  p->AddHeader (header);
225  m_sent.insert (std::make_pair (m_seq - 1, Simulator::Now ()));
226  m_socket->Send (p, 0);
227  m_next = Simulator::Schedule (m_interval, &V4Ping::Send, this);
228  delete[] data;
229 }
230 
231 void
233 {
234  NS_LOG_FUNCTION (this);
235 
237  if (m_verbose)
238  {
239  std::cout << "PING " << m_remote << " 56(84) bytes of data.\n";
240  }
241 
242  m_socket = Socket::CreateSocket (GetNode (), TypeId::LookupByName ("ns3::Ipv4RawSocketFactory"));
243  NS_ASSERT (m_socket != 0);
244  m_socket->SetAttribute ("Protocol", UintegerValue (1)); // icmp
245  m_socket->SetRecvCallback (MakeCallback (&V4Ping::Receive, this));
247  int status;
248  status = m_socket->Bind (src);
249  NS_ASSERT (status != -1);
251  status = m_socket->Connect (dst);
252  NS_ASSERT (status != -1);
253 
254  Send ();
255 }
256 void
258 {
259  NS_LOG_FUNCTION (this);
260  m_next.Cancel ();
261  m_socket->Close ();
262 
263  if (m_verbose)
264  {
265  std::ostringstream os;
266  os.precision (4);
267  os << "--- " << m_remote << " ping statistics ---\n"
268  << m_seq << " packets transmitted, " << m_recv << " received, "
269  << ((m_seq - m_recv) * 100 / m_seq) << "% packet loss, "
270  << "time " << (Simulator::Now () - m_started).GetMilliSeconds () << "ms\n";
271 
272  if (m_avgRtt.Count () > 0)
273  os << "rtt min/avg/max/mdev = " << m_avgRtt.Min () << "/" << m_avgRtt.Avg () << "/"
274  << m_avgRtt.Max () << "/" << m_avgRtt.Stddev ()
275  << " ms\n";
276  std::cout << os.str ();
277  }
278 }
279 
280 
281 } // namespace ns3
virtual void StartApplication(void)
Application specific startup code.
Definition: v4ping.cc:232
T Max() const
Maximum.
Definition: average.h:80
an Inet address class
static Ipv4Address GetAny(void)
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
uint32_t GetNApplications(void) const
Definition: node.cc:167
double Stddev() const
Standard deviation.
Definition: average.h:88
static bool ChecksumEnabled(void)
Definition: node.cc:267
#define NS_ASSERT(condition)
Definition: assert.h:64
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
#define NS_LOG_INFO(msg)
Definition: log.h:264
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Definition: simulator.h:820
double Avg() const
Sample average.
Definition: average.h:82
virtual void DoDispose(void)
Definition: v4ping.cc:80
Ptr< Application > GetApplication(uint32_t index) const
Definition: node.cc:159
Time m_started
Start time to report total ping time.
Definition: v4ping.h:76
Hold an unsigned integer type.
Definition: uinteger.h:46
Ptr< Node > GetNode() const
Definition: application.cc:103
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:502
void SetRecvCallback(Callback< void, Ptr< Socket > >)
Notify application when new data is available to be read.
Definition: socket.cc:127
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
Definition: socket.cc:70
virtual int Connect(const Address &address)=0
Initiate a connection to a remote host.
virtual void DoDispose(void)
Definition: application.cc:82
T Min() const
Minimum.
Definition: average.h:78
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
std::map< uint16_t, Time > m_sent
All sent but not answered packets. Map icmp seqno -> when sent.
Definition: v4ping.h:82
static InetSocketAddress ConvertFrom(const Address &address)
bool m_verbose
produce ping-style output if true
Definition: v4ping.h:72
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
static Time Now(void)
Definition: simulator.cc:179
EventId m_next
Next packet will be sent.
Definition: v4ping.h:80
#define NS_ASSERT_MSG(condition, message)
Definition: assert.h:86
Time Seconds(double seconds)
create ns3::Time instances in units of seconds.
Definition: nstime.h:586
virtual void StopApplication(void)
Application specific shutdown code.
Definition: v4ping.cc:257
uint32_t GetId(void) const
Definition: node.cc:105
#define NS_LOG_DEBUG(msg)
Definition: log.h:255
void Cancel(void)
Definition: event-id.cc:47
Time m_interval
Wait interval seconds between sending each packet.
Definition: v4ping.h:62
uint32_t m_recv
received packets counter
Definition: v4ping.h:74
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)=0
Read a single packet from the socket and retrieve the sender address.
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
Ipv4Address m_remote
Remote address.
Definition: v4ping.h:60
virtual int Close(void)=0
Close a socket.
uint32_t Count() const
Sample size.
Definition: average.h:76
void SetAttribute(std::string name, const AttributeValue &value)
Definition: object-base.cc:160
static bool IsMatchingType(const Address &address)
uint32_t m_size
Definition: v4ping.h:67
Average< double > m_avgRtt
Average rtt is ms.
Definition: v4ping.h:78
static TypeId LookupByName(std::string name)
Definition: type-id.cc:415
virtual uint32_t GetRxAvailable(void) const =0
void Update(T const &x)
Add new sample.
Definition: average.h:54