Allow UDP echo client to specify packet contents
authorCraig Dowell <craigdo@ee.washington.edu>
Tue, 23 Jun 2009 19:44:57 -0700
changeset 4577 84c133267507
parent 4576 96811f76c3e2
child 4578 88434ff8f0a5
Allow UDP echo client to specify packet contents
examples/udp-echo.cc
src/applications/udp-echo/udp-echo-client.cc
src/applications/udp-echo/udp-echo-client.h
src/helper/udp-echo-helper.cc
src/helper/udp-echo-helper.h
--- a/examples/udp-echo.cc	Mon Jun 22 18:29:43 2009 -0700
+++ b/examples/udp-echo.cc	Tue Jun 23 19:44:57 2009 -0700
@@ -43,30 +43,10 @@
 //
 #if 0
   LogComponentEnable ("UdpEchoExample", LOG_LEVEL_INFO);
-
-  LogComponentEnable("Object", LOG_LEVEL_ALL);
-  LogComponentEnable("Queue", LOG_LEVEL_ALL);
-  LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
-  LogComponentEnable("Channel", LOG_LEVEL_ALL);
-  LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
-  LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
-  LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
-  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
-  LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
-  LogComponentEnable("Socket", LOG_LEVEL_ALL);
-  LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
-  LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
-  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
-  LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
-  LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
-  LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
-  LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
-  LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
-  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
   LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
   LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
 #endif
-
+//
 // Allow the user to override any of the defaults and the above Bind() at
 // run-time, via command-line arguments
 //
@@ -125,6 +105,19 @@
   apps.Start (Seconds (2.0));
   apps.Stop (Seconds (10.0));
 
+#if 0
+//
+// Users may find it convenient to initialize echo packets with actual data;
+// the below lines suggest how to do this
+//
+  client.SetFill(apps.Get (0), "Hello World");
+
+  client.SetFill(apps.Get (0), 0xa5, 1024);
+
+  uint8_t fill[] = {0, 1, 2, 3, 4, 5, 6};
+  client.SetFill(apps.Get (0), fill, sizeof(fill), 1024);
+#endif
+
   std::ofstream ascii;
   ascii.open ("udp-echo.tr");
   CsmaHelper::EnablePcapAll ("udp-echo", false);
--- a/src/applications/udp-echo/udp-echo-client.cc	Mon Jun 22 18:29:43 2009 -0700
+++ b/src/applications/udp-echo/udp-echo-client.cc	Tue Jun 23 19:44:57 2009 -0700
@@ -57,9 +57,10 @@
                    UintegerValue (0),
                    MakeUintegerAccessor (&UdpEchoClient::m_peerPort),
                    MakeUintegerChecker<uint16_t> ())
-    .AddAttribute ("PacketSize", "Size of packets generated",
+    .AddAttribute ("PacketSize", "Size of echo data in outbound packets",
                    UintegerValue (100),
-                   MakeUintegerAccessor (&UdpEchoClient::m_size),
+                   MakeUintegerAccessor (&UdpEchoClient::SetDataSize,
+                                         &UdpEchoClient::GetDataSize),
                    MakeUintegerChecker<uint32_t> ())
     ;
   return tid;
@@ -71,12 +72,18 @@
   m_sent = 0;
   m_socket = 0;
   m_sendEvent = EventId ();
+  m_data = 0;
+  m_dataSize = 0;
 }
 
 UdpEchoClient::~UdpEchoClient()
 {
   NS_LOG_FUNCTION_NOARGS ();
   m_socket = 0;
+
+  delete [] m_data;
+  m_data = 0;
+  m_dataSize = 0;
 }
 
 void 
@@ -126,6 +133,106 @@
 }
 
 void 
+UdpEchoClient::SetDataSize (uint32_t dataSize)
+{
+  NS_LOG_FUNCTION (dataSize);
+
+  //
+  // If the client is setting the echo packet data size this way, we infer
+  // that she doesn't care about the contents of the packet at all, so 
+  // neither will we.
+  //
+  delete [] m_data;
+  m_data = 0;
+  m_dataSize = 0;
+  m_size = dataSize;
+}
+
+uint32_t 
+UdpEchoClient::GetDataSize (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_size;
+}
+
+void 
+UdpEchoClient::SetFill (std::string fill)
+{
+  NS_LOG_FUNCTION (fill);
+
+  uint32_t dataSize = fill.size () + 1;
+
+  if (dataSize != m_dataSize)
+    {
+      delete [] m_data;
+      m_data = new uint8_t [dataSize];
+      m_dataSize = dataSize;
+    }
+
+  memcpy (m_data, fill.c_str (), dataSize);
+
+  //
+  // Overwrite packet size attribute.
+  //
+  m_size = dataSize;
+}
+
+void 
+UdpEchoClient::SetFill (uint8_t fill, uint32_t dataSize)
+{
+  if (dataSize != m_dataSize)
+    {
+      delete [] m_data;
+      m_data = new uint8_t [dataSize];
+      m_dataSize = dataSize;
+    }
+
+  memset (m_data, fill, dataSize);
+
+  //
+  // Overwrite packet size attribute.
+  //
+  m_size = dataSize;
+}
+
+void 
+UdpEchoClient::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
+{
+  if (dataSize != m_dataSize)
+    {
+      delete [] m_data;
+      m_data = new uint8_t [dataSize];
+      m_dataSize = dataSize;
+    }
+
+  if (fillSize >= dataSize)
+    {
+      memcpy (m_data, fill, dataSize);
+      return;
+    }
+
+  //
+  // Do all but the final fill.
+  //
+  uint32_t filled = 0;
+  while (filled + fillSize < dataSize)
+    {
+      memcpy (&m_data[filled], fill, fillSize);
+      filled += fillSize;
+    }
+
+  //
+  // Last fill may be partial
+  //
+  memcpy(&m_data[filled], fill, dataSize - filled);
+
+  //
+  // Overwrite packet size attribute.
+  //
+  m_size = dataSize;
+}
+
+void 
 UdpEchoClient::ScheduleTransmit (Time dt)
 {
   NS_LOG_FUNCTION_NOARGS ();
@@ -139,8 +246,32 @@
 
   NS_ASSERT (m_sendEvent.IsExpired ());
 
-  Ptr<Packet> p = Create<Packet> (m_size);
-  m_socket->Send (p);
+  if (m_dataSize)
+    {
+      //
+      // If m_dataSize is non-zero, we have a data buffer of the same size that we
+      // are expected to copy and send.  This state of affairs is created if one of
+      // the Fill functions is called.  In this case, m_size must have been set
+      // to agree with m_dataSize
+      //
+      NS_ASSERT_MSG (m_dataSize == m_size, "UdpEchoClient::Send(): m_size and m_dataSize inconsistent");
+      NS_ASSERT_MSG (m_data, "UdpEchoClient::Send(): m_dataSize but no m_data");
+      Ptr<Packet> p = Create<Packet> (m_data, m_dataSize);
+      m_socket->Send (p);
+    }
+  else
+    {
+      //
+      // If m_dataSize is zero, the client has indicated that she doesn't care 
+      // about the data itself either by specifying the data size by setting
+      // the corresponding atribute or by not calling a SetFill function.  In 
+      // this case, we don't worry about it either.  But we do allow m_size
+      // to have a value different from the (zero) m_dataSize.
+      //
+      Ptr<Packet> p = Create<Packet> (m_size);
+      m_socket->Send (p);
+    }
+
   ++m_sent;
 
   NS_LOG_INFO ("Sent " << m_size << " bytes to " << m_peerAddress);
--- a/src/applications/udp-echo/udp-echo-client.h	Mon Jun 22 18:29:43 2009 -0700
+++ b/src/applications/udp-echo/udp-echo-client.h	Tue Jun 23 19:44:57 2009 -0700
@@ -46,6 +46,75 @@
 
   void SetRemote (Ipv4Address ip, uint16_t port);
 
+  /**
+   * Set the data size of the packet (the number of bytes that are sent as data
+   * to the server).  The contents of the data are set to unspecified (don't
+   * care) by this call.
+   *
+   * \warn If you have set the fill data for the echo client using one of the
+   * SetFill calls, this will undo those effects.
+   *
+   * \param dataSize The size of the echo data you want to sent.
+   */
+  void SetDataSize (uint32_t dataSize);
+
+  /**
+   * Get the number of data bytes that will be sent to the server.
+   *
+   * \warn The number of bytes may be modified by calling any one of the 
+   * SetFill methods.  If you have called SetFill, then the number of 
+   * data bytes will correspond to the size of an initialized data buffer.
+   * If you have not called a SetFill method, the number of data bytes will
+   * correspond to the number of don't care bytes that will be sent.
+   *
+   * \returns The number of data bytes.
+   */
+  uint32_t GetDataSize (void) const;
+
+  /**
+   * Set the data fill of the packet (what is sent as data to the server) to 
+   * the zero-terminated contents of the fill string string.
+   *
+   * \warn The size of resulting echo packets will be automatically adjusted
+   * to reflect the size of the fill string -- this means that the PacketSize
+   * attribute may be changed as a result of this call.
+   *
+   * \param fill The string to use as the actual echo data bytes.
+   */
+  void SetFill (std::string fill);
+
+  /**
+   * Set the data fill of the packet (what is sent as data to the server) to 
+   * the repeated contents of the fill byte.  i.e., the fill byte will be 
+   * used to initialize the contents of the data packet.
+   * 
+   * \warn The size of resulting echo packets will be automatically adjusted
+   * to reflect the dataSize parameter -- this means that the PacketSize
+   * attribute may be changed as a result of this call.
+   *
+   * \param fill The byte to be repeated in constructing the packet data..
+   * \param dataSize The desired size of the resulting echo packet data.
+   */
+  void SetFill (uint8_t fill, uint32_t dataSize);
+
+  /**
+   * Set the data fill of the packet (what is sent as data to the server) to
+   * the contents of the fill buffer, repeated as many times as is required.
+   *
+   * Initializing the packet to the contents of a provided single buffer is 
+   * accomplished by setting the fillSize set to your desired dataSize
+   * (and providing an appropriate buffer).
+   *
+   * \warn The size of resulting echo packets will be automatically adjusted
+   * to reflect the dataSize parameter -- this means that the PacketSize
+   * attribute of the Application may be changed as a result of this call.
+   *
+   * \param fill The fill pattern to use when constructing packets.
+   * \param fillSize The number of bytes in the provided fill pattern.
+   * \param dataSize The desired size of the final echo data.
+   */
+  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
+
 protected:
   virtual void DoDispose (void);
 
@@ -63,6 +132,9 @@
   Time m_interval;
   uint32_t m_size;
 
+  uint32_t m_dataSize;
+  uint8_t *m_data;
+
   uint32_t m_sent;
   Ptr<Socket> m_socket;
   Ipv4Address m_peerAddress;
--- a/src/helper/udp-echo-helper.cc	Mon Jun 22 18:29:43 2009 -0700
+++ b/src/helper/udp-echo-helper.cc	Tue Jun 23 19:44:57 2009 -0700
@@ -88,6 +88,24 @@
   m_factory.Set (name, value);
 }
 
+void
+UdpEchoClientHelper::SetFill (Ptr<Application> app, std::string fill)
+{
+  app->GetObject<UdpEchoClient>()->SetFill (fill);
+}
+
+void
+UdpEchoClientHelper::SetFill (Ptr<Application> app, uint8_t fill, uint32_t dataLength)
+{
+  app->GetObject<UdpEchoClient>()->SetFill (fill, dataLength);
+}
+
+void
+UdpEchoClientHelper::SetFill (Ptr<Application> app, uint8_t *fill, uint32_t fillLength, uint32_t dataLength)
+{
+  app->GetObject<UdpEchoClient>()->SetFill (fill, fillLength, dataLength);
+}
+
 ApplicationContainer
 UdpEchoClientHelper::Install (Ptr<Node> node) const
 {
--- a/src/helper/udp-echo-helper.h	Mon Jun 22 18:29:43 2009 -0700
+++ b/src/helper/udp-echo-helper.h	Tue Jun 23 19:44:57 2009 -0700
@@ -52,6 +52,57 @@
 
   void SetAttribute (std::string name, const AttributeValue &value);
 
+  /**
+   * Given a pointer to a UdpEchoClient application, set the data fill of the 
+   * packet (what is sent as data to the server) to the contents of the fill
+   * string (including the trailing zero terminator).
+   *
+   * \warn The size of resulting echo packets will be automatically adjusted
+   * to reflect the size of the fill string -- this means that the PacketSize
+   * attribute may be changed as a result of this call.
+   *
+   * \param app Smart pointer to the application (real type must be UdpEchoClient).
+   * \param fill The string to use as the actual echo data bytes.
+   */
+  void SetFill (Ptr<Application> app, std::string fill);
+
+  /**
+   * Given a pointer to a UdpEchoClient application, set the data fill of the 
+   * packet (what is sent as data to the server) to the contents of the fill
+   * byte.
+   *
+   * The fill byte will be used to initialize the contents of the data packet.
+   * 
+   * \warn The size of resulting echo packets will be automatically adjusted
+   * to reflect the dataLength parameter -- this means that the PacketSize
+   * attribute may be changed as a result of this call.
+   *
+   * \param app Smart pointer to the application (real type must be UdpEchoClient).
+   * \param fill The byte to be repeated in constructing the packet data..
+   * \param dataLength The desired length of the resulting echo packet data.
+   */
+  void SetFill (Ptr<Application> app, uint8_t fill, uint32_t dataLength);
+
+  /**
+   * Given a pointer to a UdpEchoClient application, set the data fill of the 
+   * packet (what is sent as data to the server) to the contents of the fill
+   * buffer, repeated as many times as is required.
+   *
+   * Initializing the fill to the contents of a single buffer is accomplished
+   * by providing a complete buffer with fillLength set to your desired 
+   * dataLength
+   *
+   * \warn The size of resulting echo packets will be automatically adjusted
+   * to reflect the dataLength parameter -- this means that the PacketSize
+   * attribute of the Application may be changed as a result of this call.
+   *
+   * \param app Smart pointer to the application (real type must be UdpEchoClient).
+   * \param fill The fill pattern to use when constructing packets.
+   * \param fillLength The number of bytes in the provided fill pattern.
+   * \param dataLength The desired length of the final echo data.
+   */
+  void SetFill (Ptr<Application> app, uint8_t *fill, uint32_t fillLength, uint32_t dataLength);
+
   ApplicationContainer Install (Ptr<Node> node) const;
   ApplicationContainer Install (std::string nodeName) const;
   ApplicationContainer Install (NodeContainer c) const;