--- a/.hgtags Fri Jul 06 14:19:40 2007 -0700
+++ b/.hgtags Fri Jul 06 14:39:59 2007 -0700
@@ -1,3 +1,4 @@
56928998e05c9c11f5f3aefe79be8d2843e0db88 release ns-3.0.1
7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2
+0dc81e76166c56aaae64da48b673b62155943aad packet-history-working
38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3
--- a/SConstruct Fri Jul 06 14:19:40 2007 -0700
+++ b/SConstruct Fri Jul 06 14:39:59 2007 -0700
@@ -190,6 +190,8 @@
'chunk.cc',
'header.cc',
'trailer.cc',
+ 'packet-printer.cc',
+ 'packet-metadata.cc',
'packet.cc',
'tags.cc',
'pcap-writer.cc',
@@ -211,6 +213,8 @@
'trailer.h',
'tags.h',
'packet.h',
+ 'packet-printer.h',
+ 'packet-metadata.h',
'uv-trace-source.h',
'sv-trace-source.h',
'fv-trace-source.h',
@@ -306,8 +310,6 @@
'udp-impl.cc',
])
inode.add_headers ([
- 'ipv4-header.h',
- 'udp-header.h',
'ipv4-checksum.h',
'arp-header.h',
'arp-cache.h',
@@ -337,6 +339,8 @@
'internet-node.h',
'ascii-trace.h',
'pcap-trace.h',
+ 'ipv4-header.h',
+ 'udp-header.h',
])
@@ -370,9 +374,9 @@
bench_object.add_source('bench-object.cc')
bench_packets = build.Ns3Module('bench-packets', 'utils')
-#ns3.add(bench_packets)
+ns3.add(bench_packets)
bench_packets.set_executable()
-bench_packets.add_dep('core')
+bench_packets.add_deps (['core', 'common'])
bench_packets.add_source('bench-packets.cc')
bench_simu = build.Ns3Module('bench-simulator', 'utils')
@@ -396,6 +400,13 @@
sample_debug.add_source('main-debug.cc')
sample_debug.add_source('main-debug-other.cc')
+sample_packet_printer = build.Ns3Module('sample-packet-printer', 'samples')
+sample_packet_printer.set_executable()
+ns3.add(sample_packet_printer)
+sample_packet_printer.add_deps (['common', 'internet-node'])
+sample_packet_printer.add_source('main-packet-printer.cc')
+
+
sample_callback = build.Ns3Module('sample-callback', 'samples')
sample_callback.set_executable()
ns3.add(sample_callback)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-printer.cc Fri Jul 06 14:39:59 2007 -0700
@@ -0,0 +1,197 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "ns3/packet.h"
+#include "ns3/header.h"
+#include "ns3/packet-printer.h"
+#include "ns3/ipv4-header.h"
+#include "ns3/udp-header.h"
+
+using namespace ns3;
+
+// This sample file shows how to use the Packet metadata facility
+//
+// Packets are stored as ``packed'' data structures, to facilitate
+// fragmentation and network emulation. However, when debugging a program,
+// or for certain tracing applications, it may be convenient to dump out
+// the contents of a packet header in a human-friendly form.
+//
+// To do this, a few things are needed:
+// i) enable the metadata facility (disabled by default, because it causes
+// a small performance hit
+// ii) decide on whether you want to use a default or customized (you
+// provide your own) routine to dump a particular header
+//
+// This sample steps through two routines; one to use the default
+// printing of IPv4 and UDP headers, and one to show a non-default case.
+// There is a lot of emphasis in this sample of how this facility
+// interacts with packet fragmentation.
+
+void DefaultPrint (void)
+{
+ // We create a packet with 1000 bytes of zero payload
+ // and add 3 headers to this packet.
+ Packet p (1000);
+ Ipv4Header ipv4;
+ UdpHeader udp;
+ ipv4.SetSource (Ipv4Address ("192.168.0.1"));
+ ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
+ udp.SetSource (1025);
+ udp.SetDestination (80);
+ udp.SetPayloadSize (1000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
+
+ std::cout << "full packet size=" << p.GetSize () << std::endl;
+ // Here, invoke the default Print routine, directed to std out
+ p.Print (std::cout);
+ std::cout << std::endl;
+
+
+ // Now, we fragment our packet in 3 consecutive pieces.
+ Packet p1 = p.CreateFragment (0, 2);
+ Packet p2 = p.CreateFragment (2, 1000);
+ Packet p3 = p.CreateFragment (1002, 26);
+
+ std::cout << "fragment1" << std::endl;
+ p1.Print (std::cout);
+ std::cout << std::endl;
+ std::cout << "fragment2" << std::endl;
+ p2.Print (std::cout);
+ std::cout << std::endl;
+ std::cout << "fragment3" << std::endl;
+ p3.Print (std::cout);
+ std::cout << std::endl;
+
+ // And, finally, we re-aggregate the 3 consecutive pieces.
+ Packet aggregate = p1;
+ aggregate.AddAtEnd (p2);
+ aggregate.AddAtEnd (p3);
+ std::cout << "aggregated" << std::endl;
+ aggregate.Print (std::cout);
+ std::cout << std::endl;
+}
+
+// The below functions are used in place of default versions, in the
+// non-default case below. For instance, DoPrintIpv4Header will print
+// out less IPv4 header information than the default print function
+void
+DoPrintDefault (std::ostream &os,uint32_t packetUid, uint32_t size,
+ std::string &name, struct PacketPrinter::FragmentInformation info)
+{
+ os << name <<" (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
+}
+void
+DoPrintPayload (std::ostream & os,uint32_t packetUid,uint32_t size,
+ struct PacketPrinter::FragmentInformation info)
+{
+ os << "PAYLOAD (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
+}
+void
+DoPrintIpv4Header (std::ostream &os, uint32_t packetUid, uint32_t size, const Ipv4Header *ipv4)
+{
+ os << "IPV4 " << ipv4->GetSource () << " > " << ipv4->GetDestination ();
+}
+void
+DoPrintIpv4HeaderFragment (std::ostream &os, uint32_t packetUid, uint32_t size,
+ std::string &name, struct PacketPrinter::FragmentInformation info)
+{
+ os << "IPV4 fragment";
+}
+
+// This function walks through a non-default case. A few features of
+// the API (defined in common/packet-printer.h) are shown.
+//
+void NonDefaultPrint (void)
+{
+ // create an adhoc packet printer.
+ PacketPrinter printer;
+ // print from first header to last trailer
+ printer.PrintForward ();
+ // set a string separator automatically inserted
+ // between each call to a printing function.
+ printer.SetSeparator (" - ");
+ // set the default print function: invoked if no
+ // specialized function has been provided for a header
+ // or trailer
+ printer.AddDefaultPrinter (MakeCallback (&DoPrintDefault));
+ // set the payload print function
+ printer.AddPayloadPrinter (MakeCallback (&DoPrintPayload));
+ // set the print function for the header type Ipv4Header.
+ printer.AddHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
+ MakeCallback (&DoPrintIpv4HeaderFragment));
+
+
+ // We create a packet with 1000 bytes of zero payload
+ Packet p (1000);
+ Ipv4Header ipv4;
+ UdpHeader udp;
+ ipv4.SetSource (Ipv4Address ("192.168.0.1"));
+ ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
+ udp.SetSource (1025);
+ udp.SetDestination (80);
+ udp.SetPayloadSize (1000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
+
+ std::cout << "full packet size=" << p.GetSize () << std::endl;
+ p.Print (std::cout, printer);
+ std::cout << std::endl;
+
+
+ // fragment our packet in 3 pieces
+ Packet p1 = p.CreateFragment (0, 2);
+ Packet p2 = p.CreateFragment (2, 1000);
+ Packet p3 = p.CreateFragment (1002, 26);
+ std::cout << "fragment1" << std::endl;
+ p1.Print (std::cout, printer);
+ std::cout << std::endl;
+ std::cout << "fragment2" << std::endl;
+ p2.Print (std::cout, printer);
+ std::cout << std::endl;
+ std::cout << "fragment3" << std::endl;
+ p3.Print (std::cout, printer);
+ std::cout << std::endl;
+
+ // aggregate all 3 fragments of the original packet
+ // to reconstruct a copy of the original packet.
+ Packet aggregate = p1;
+ aggregate.AddAtEnd (p2);
+ aggregate.AddAtEnd (p3);
+ std::cout << "aggregated" << std::endl;
+ aggregate.Print (std::cout, printer);
+ std::cout << std::endl;
+}
+
+
+
+int main (int argc, char *argv[])
+{
+ Packet::EnableMetadata ();
+
+ std::cout << "DefaultPrint()" << std::endl;
+ DefaultPrint ();
+
+ std::cout << std::endl << "NonDefaultPrint()" << std::endl;
+ NonDefaultPrint ();
+
+ return 0;
+}
--- a/samples/main-packet.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/samples/main-packet.cc Fri Jul 06 14:39:59 2007 -0700
@@ -15,6 +15,7 @@
void SetData (uint16_t data);
uint16_t GetData (void) const;
private:
+ virtual std::string DoGetName (void) const;
virtual void PrintTo (std::ostream &os) const;
virtual void SerializeTo (Buffer::Iterator start) const;
virtual uint32_t DeserializeFrom (Buffer::Iterator start);
@@ -27,6 +28,11 @@
{}
MyHeader::~MyHeader ()
{}
+std::string
+MyHeader::DoGetName (void) const
+{
+ return "MyHeader";
+}
void
MyHeader::PrintTo (std::ostream &os) const
{
--- a/src/common/buffer.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/buffer.cc Fri Jul 06 14:39:59 2007 -0700
@@ -224,7 +224,7 @@
uint32_t newSize = m_size + end;
struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
memcpy (newData->m_data, GetStart (), m_size);
- newData->m_initialStart = m_data->m_initialStart;
+ newData->m_initialStart = m_data->m_initialStart - m_start;
m_data->m_count--;
if (m_data->m_count == 0)
{
@@ -663,6 +663,12 @@
i.Prev (4);
i.WriteU8 (1, 4);
+ buffer = Buffer (1);
+ buffer.AddAtEnd (100);
+ i = buffer.End ();
+ i.Prev (100);
+ i.WriteU8 (1, 100);
+
return ok;
}
--- a/src/common/buffer.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/buffer.h Fri Jul 06 14:39:59 2007 -0700
@@ -320,6 +320,8 @@
*/
inline Buffer::Iterator End (void) const;
+ void TransformIntoRealBuffer (void) const;
+
inline Buffer (Buffer const &o);
inline Buffer &operator = (Buffer const &o);
inline Buffer ();
@@ -337,7 +339,6 @@
typedef std::vector<struct Buffer::BufferData*> BufferDataList;
inline uint8_t *GetStart (void) const;
- void TransformIntoRealBuffer (void) const;
static void Recycle (struct Buffer::BufferData *data);
static struct Buffer::BufferData *Create (void);
static struct Buffer::BufferData *Allocate (uint32_t size, uint32_t start);
@@ -543,6 +544,8 @@
{
NS_ASSERT (start.m_data == end.m_data);
NS_ASSERT (start.m_current <= end.m_current);
+ NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
+ NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
NS_ASSERT (m_data != start.m_data);
uint32_t size = end.m_current - start.m_current;
uint8_t *src = start.m_data + start.GetIndex (size);
--- a/src/common/chunk.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/chunk.cc Fri Jul 06 14:39:59 2007 -0700
@@ -30,6 +30,11 @@
Chunk::~Chunk ()
{}
+std::string
+Chunk::GetName (void) const
+{
+ return DoGetName ();
+}
void
Chunk::Print (std::ostream &os) const
{
--- a/src/common/chunk.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/chunk.h Fri Jul 06 14:39:59 2007 -0700
@@ -33,11 +33,13 @@
Chunk ();
virtual ~Chunk ();
+ std::string GetName (void) const;
void Print (std::ostream &os) const;
uint32_t GetSize (void) const;
void Serialize (Buffer::Iterator start) const;
uint32_t Deserialize (Buffer::Iterator start);
private:
+ virtual std::string DoGetName (void) const = 0;
virtual void PrintTo (std::ostream &os) const = 0;
virtual uint32_t GetSerializedSize (void) const = 0;
virtual void SerializeTo (Buffer::Iterator i) const = 0;
--- a/src/common/data-rate.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/data-rate.cc Fri Jul 06 14:39:59 2007 -0700
@@ -23,9 +23,8 @@
#include "ns3/nstime.h"
#include "ns3/fatal-error.h"
-namespace {
-bool
+static bool
DoParse (const std::string s, uint64_t *v)
{
std::string::size_type n = s.find_first_not_of("0123456789.");
@@ -123,7 +122,6 @@
return true;
}
-}
namespace ns3 {
--- a/src/common/header.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/header.h Fri Jul 06 14:39:59 2007 -0700
@@ -42,8 +42,25 @@
virtual ~Header ();
private:
/**
+ * \returns a user-readable name to identify this type of header.
+ *
+ * The string returned is expected to be a single word with
+ * all capital letters
+ */
+ virtual std::string DoGetName (void) const = 0;
+ /**
* \param os the std output stream in which this
* protocol header must print itself.
+ *
+ * Although the header is free to format its output as it
+ * wishes, it is recommended to follow a few rules to integrate
+ * with the packet pretty printer:
+ * - start with flags, small field values located between a
+ * pair of parens. Values should be separated by whitespace.
+ * - follow the parens with the important fields, separated by
+ * whitespace.
+ * i.e.:
+ * (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
*/
virtual void PrintTo (std::ostream &os) const = 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata.cc Fri Jul 06 14:39:59 2007 -0700
@@ -0,0 +1,1714 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include <utility>
+#include <list>
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/debug.h"
+#include "packet-metadata.h"
+#include "chunk.h"
+#include "buffer.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("PacketMetadata");
+
+namespace ns3 {
+
+bool PacketMetadata::m_enable = false;
+uint32_t PacketMetadata::m_maxSize = 0;
+uint16_t PacketMetadata::m_chunkUid = 0;
+PacketMetadata::DataFreeList PacketMetadata::m_freeList;
+bool g_optOne = false;
+
+void
+PacketMetadata::Enable (void)
+{
+ m_enable = true;
+}
+
+void
+PacketMetadata::SetOptOne (bool optOne)
+{
+ g_optOne = optOne;
+}
+
+void
+PacketMetadata::ReserveCopy (uint32_t size)
+{
+ struct PacketMetadata::Data *newData = PacketMetadata::Create (m_used + size);
+ memcpy (newData->m_data, m_data->m_data, m_used);
+ newData->m_dirtyEnd = m_used;
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ PacketMetadata::Recycle (m_data);
+ }
+ m_data = newData;
+ if (m_head != 0xffff)
+ {
+ uint8_t *start;
+ NS_ASSERT (m_tail != 0xffff);
+ // clear the next field of the tail
+ start = &m_data->m_data[m_tail];
+ Append16 (0xffff, start);
+ // clear the prev field of the head
+ start = &m_data->m_data[m_head] + 2;
+ Append16 (0xffff, start);
+ }
+}
+void
+PacketMetadata::Reserve (uint32_t size)
+{
+ NS_ASSERT (m_data != 0);
+ if (m_data->m_size >= m_used + size &&
+ (m_head == 0xffff ||
+ m_data->m_count == 1 ||
+ m_data->m_dirtyEnd == m_used))
+ {
+ /* enough room, not dirty. */
+ }
+ else
+ {
+ /* (enough room and dirty) or (not enough room) */
+ ReserveCopy (size);
+ }
+}
+
+uint32_t
+PacketMetadata::GetUleb128Size (uint32_t value) const
+{
+ if (value < 0x80)
+ {
+ return 1;
+ }
+ if (value < 0x4000)
+ {
+ return 2;
+ }
+ if (value < 0x200000)
+ {
+ return 3;
+ }
+ if (value < 0x10000000)
+ {
+ return 4;
+ }
+ return 5;
+}
+uint32_t
+PacketMetadata::ReadUleb128 (const uint8_t **pBuffer) const
+{
+ const uint8_t *buffer = *pBuffer;
+ uint32_t result = 0;
+ uint8_t byte;
+ result = 0;
+ byte = buffer[0];
+ result = (byte & (~0x80));
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 1;
+ return result;
+ }
+ byte = buffer[1];
+ result |= (byte & (~0x80)) << 7;
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 2;
+ return result;
+ }
+ byte = buffer[2];
+ result |= (byte & (~0x80)) << 14;
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 3;
+ return result;
+ }
+ byte = buffer[3];
+ result |= (byte & (~0x80)) << 21;
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 4;
+ return result;
+ }
+ byte = buffer[4];
+ result |= (byte & (~0x80)) << 28;
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 5;
+ return result;
+ }
+ /* This means that the LEB128 number was not valid.
+ * ie: the last (5th) byte did not have the high-order bit zeroed.
+ */
+ NS_ASSERT (false);
+ return 0;
+}
+
+void
+PacketMetadata::Append16 (uint16_t value, uint8_t *buffer)
+{
+ buffer[0] = value & 0xff;
+ value >>= 8;
+ buffer[1] = value;
+}
+bool
+PacketMetadata::TryToAppendFast (uint32_t value, uint8_t **pBuffer, uint8_t *end)
+{
+ uint8_t *start = *pBuffer;
+ if (value < 0x80 && start < end)
+ {
+ start[0] = value;
+ *pBuffer = start + 1;
+ return true;
+ }
+ if (value < 0x4000 && start + 1 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ start[1] = value;
+ *pBuffer = start + 2;
+ return true;
+ }
+ return false;
+}
+bool
+PacketMetadata::TryToAppend16 (uint16_t value, uint8_t **pBuffer, uint8_t *end)
+{
+ uint8_t *start = *pBuffer;
+ if (start + 1 < end)
+ {
+ start[0] = value & 0xff;
+ start[1] = value >> 8;
+ *pBuffer = start + 2;
+ return true;
+ }
+ return false;
+}
+bool
+PacketMetadata::TryToAppend32 (uint32_t value, uint8_t **pBuffer, uint8_t *end)
+{
+ uint8_t *start = *pBuffer;
+ if (start + 3 < end)
+ {
+ start[0] = value & 0xff;
+ start[1] = (value >> 8) & 0xff;
+ start[2] = (value >> 16) & 0xff;
+ start[3] = (value >> 24) & 0xff;
+ *pBuffer = start + 4;
+ return true;
+ }
+ return false;
+}
+bool
+PacketMetadata::TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end)
+{
+ uint8_t *start = *pBuffer;
+ if (value < 0x80 && start < end)
+ {
+ start[0] = value;
+ *pBuffer = start + 1;
+ return true;
+ }
+ if (value < 0x4000 && start + 1 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ start[1] = value;
+ *pBuffer = start + 2;
+ return true;
+ }
+ if (value < 0x200000 && start + 2 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[2] = value;
+ *pBuffer = start + 3;
+ return true;
+ }
+ if (value < 0x10000000 && start + 3 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[2] = 0x80 | byte;
+ value >>= 7;
+ start[3] = value;
+ *pBuffer = start + 4;
+ return true;
+ }
+ if (start + 4 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[2] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[3] = 0x80 | byte;
+ value >>= 7;
+ start[4] = value;
+ *pBuffer = start + 5;
+ return true;
+ }
+ return false;
+}
+
+void
+PacketMetadata::AppendValueExtra (uint32_t value, uint8_t *buffer)
+{
+ if (value < 0x200000)
+ {
+ uint8_t byte = value & (~0x80);
+ buffer[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[2] = value;
+ return;
+ }
+ if (value < 0x10000000)
+ {
+ uint8_t byte = value & (~0x80);
+ buffer[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[2] = 0x80 | byte;
+ value >>= 7;
+ buffer[3] = value;
+ return;
+ }
+ {
+ uint8_t byte = value & (~0x80);
+ buffer[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[2] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[3] = 0x80 | byte;
+ value >>= 7;
+ buffer[4] = value;
+ }
+}
+
+void
+PacketMetadata::AppendValue (uint32_t value, uint8_t *buffer)
+{
+ if (value < 0x80)
+ {
+ buffer[0] = value;
+ return;
+ }
+ if (value < 0x4000)
+ {
+ uint8_t byte = value & (~0x80);
+ buffer[0] = 0x80 | byte;
+ value >>= 7;
+ buffer[1] = value;
+ return;
+ }
+ AppendValueExtra (value, buffer);
+}
+
+void
+PacketMetadata::UpdateTail (uint16_t written)
+{
+ if (m_head == 0xffff)
+ {
+ NS_ASSERT (m_tail == 0xffff);
+ m_head = m_used;
+ m_tail = m_used;
+ }
+ else
+ {
+ NS_ASSERT (m_tail != 0xffff);
+ // overwrite the next field of the previous tail of the list.
+ uint8_t *previousTail = &m_data->m_data[m_tail];
+ Append16 (m_used, previousTail);
+ // update the tail of the list to the new node.
+ m_tail = m_used;
+ }
+ NS_ASSERT (m_tail != 0xffff);
+ NS_ASSERT (m_head != 0xffff);
+ NS_ASSERT (written >= 8);
+ m_used += written;
+ m_data->m_dirtyEnd = m_used;
+}
+
+
+void
+PacketMetadata::UpdateHead (uint16_t written)
+{
+ if (m_head == 0xffff)
+ {
+ NS_ASSERT (m_tail == 0xffff);
+ m_head = m_used;
+ m_tail = m_used;
+ }
+ else
+ {
+ NS_ASSERT (m_head != 0xffff);
+ // overwrite the prev field of the previous head of the list.
+ uint8_t *previousHead = &m_data->m_data[m_head + 2];
+ Append16 (m_used, previousHead);
+ // update the head of list to the new node.
+ m_head = m_used;
+ }
+ NS_ASSERT (m_tail != 0xffff);
+ NS_ASSERT (m_head != 0xffff);
+ NS_ASSERT (written >= 8);
+ m_used += written;
+ m_data->m_dirtyEnd = m_used;
+}
+
+uint16_t
+PacketMetadata::AddSmall (const struct PacketMetadata::SmallItem *item)
+{
+ NS_ASSERT (m_data != 0);
+ NS_ASSERT (m_used != item->prev && m_used != item->next);
+ if (g_optOne)
+ {
+ uint32_t typeUidSize = GetUleb128Size (item->typeUid);
+ uint32_t sizeSize = GetUleb128Size (item->size);
+ uint32_t n = typeUidSize + sizeSize + 2 + 2 + 2;
+ restart:
+ if (m_used + n <= m_data->m_size &&
+ (m_head == 0xffff ||
+ m_data->m_count == 1 ||
+ m_used == m_data->m_dirtyEnd))
+ {
+ uint8_t *buffer = &m_data->m_data[m_used];
+ Append16 (item->next, buffer);
+ buffer += 2;
+ Append16 (item->prev, buffer);
+ buffer += 2;
+ AppendValue (item->typeUid, buffer);
+ buffer += typeUidSize;
+ AppendValue (item->size, buffer);
+ buffer += sizeSize;
+ Append16 (item->chunkUid, buffer);
+ }
+ else
+ {
+ ReserveCopy (n);
+ goto restart;
+ }
+ return n;
+ }
+ append:
+ uint8_t *start = &m_data->m_data[m_used];
+ uint8_t *end = &m_data->m_data[m_data->m_size];
+ if (end - start >= 8 &&
+ (m_head == 0xffff ||
+ m_data->m_count == 1 ||
+ m_used == m_data->m_dirtyEnd))
+ {
+ uint8_t *buffer = start;
+
+ Append16 (item->next, buffer);
+ buffer += 2;
+ Append16 (item->prev, buffer);
+ buffer += 2;
+ if (TryToAppendFast (item->typeUid, &buffer, end) &&
+ TryToAppendFast (item->size, &buffer, end) &&
+ TryToAppend16 (item->chunkUid, &buffer, end))
+ {
+ uintptr_t written = buffer - start;
+ NS_ASSERT (written <= 0xffff);
+ NS_ASSERT (written >= 8);
+ return written;
+ }
+ }
+ uint32_t n = GetUleb128Size (item->typeUid);
+ n += GetUleb128Size (item->size);
+ n += 2;
+ n += 2 + 2;
+ Reserve (n);
+ goto append;
+}
+
+uint16_t
+PacketMetadata::AddBig (uint32_t next, uint32_t prev,
+ const PacketMetadata::SmallItem *item,
+ const PacketMetadata::ExtraItem *extraItem)
+{
+ NS_ASSERT (m_data != 0);
+ uint32_t typeUid = ((item->typeUid & 0x1) == 0x1)?item->typeUid:item->typeUid+1;
+ NS_ASSERT (m_used != prev && m_used != next);
+ append:
+ uint8_t *start = &m_data->m_data[m_used];
+ uint8_t *end = &m_data->m_data[m_data->m_size];
+ if (end - start >= 14 &&
+ (m_head == 0xffff ||
+ m_data->m_count == 1 ||
+ m_used == m_data->m_dirtyEnd))
+ {
+ uint8_t *buffer = start;
+
+ Append16 (next, buffer);
+ buffer += 2;
+ Append16 (prev, buffer);
+ buffer += 2;
+ if (TryToAppend (typeUid, &buffer, end) &&
+ TryToAppend (item->size, &buffer, end) &&
+ TryToAppend16 (item->chunkUid, &buffer, end) &&
+ TryToAppend (extraItem->fragmentStart, &buffer, end) &&
+ TryToAppend (extraItem->fragmentEnd, &buffer, end) &&
+ TryToAppend32 (extraItem->packetUid, &buffer, end))
+ {
+ uintptr_t written = buffer - start;
+ NS_ASSERT (written <= 0xffff);
+ NS_ASSERT (written >= 14);
+ return written;
+ }
+ }
+
+ uint32_t n = GetUleb128Size (typeUid);
+ n += GetUleb128Size (item->size);
+ n += 2;
+ n += GetUleb128Size (extraItem->fragmentStart);
+ n += GetUleb128Size (extraItem->fragmentEnd);
+ n += 4;
+ n += 2 + 2;
+ ReserveCopy (n);
+ goto append;
+}
+
+void
+PacketMetadata::ReplaceTail (PacketMetadata::SmallItem *item,
+ PacketMetadata::ExtraItem *extraItem,
+ uint32_t available)
+{
+ NS_ASSERT (m_data != 0);
+ if (available >= 14 &&
+ m_data->m_count == 1)
+ {
+ uint8_t *buffer = &m_data->m_data[m_tail];
+ uint8_t *end = buffer + available;
+
+ Append16 (item->next, buffer);
+ buffer += 2;
+ Append16 (item->prev, buffer);
+ buffer += 2;
+ if (TryToAppend (item->typeUid, &buffer, end) &&
+ TryToAppend (item->size, &buffer, end) &&
+ TryToAppend16 (item->chunkUid, &buffer, end) &&
+ TryToAppend (extraItem->fragmentStart, &buffer, end) &&
+ TryToAppend (extraItem->fragmentEnd, &buffer, end) &&
+ TryToAppend32 (extraItem->packetUid, &buffer, end))
+ {
+ m_used = buffer - &m_data->m_data[0];
+ m_data->m_dirtyEnd = m_used;
+ return;
+ }
+ }
+
+ // create a copy of the packet.
+ PacketMetadata h (m_packetUid, 0);
+ uint16_t current = m_head;
+ while (current != 0xffff && current != m_tail)
+ {
+ struct PacketMetadata::SmallItem tmpItem;
+ PacketMetadata::ExtraItem tmpExtraItem;
+ ReadItems (current, &tmpItem, &tmpExtraItem);
+ uint16_t written = h.AddBig (0xffff, h.m_tail,
+ &tmpItem, &tmpExtraItem);
+ h.UpdateTail (written);
+ }
+ // append new tail.
+ uint16_t written = h.AddBig (0xffff, h.m_tail, item, extraItem);
+ h.UpdateTail (written);
+
+ *this = h;
+}
+
+uint32_t
+PacketMetadata::ReadItems (uint16_t current,
+ struct PacketMetadata::SmallItem *item,
+ struct PacketMetadata::ExtraItem *extraItem) const
+{
+ const uint8_t *buffer = &m_data->m_data[current];
+ item->next = buffer[0];
+ item->next |= (buffer[1]) << 8;
+ item->prev = buffer[2];
+ item->prev |= (buffer[3]) << 8;
+ buffer += 4;
+ item->typeUid = ReadUleb128 (&buffer);
+ item->size = ReadUleb128 (&buffer);
+ item->chunkUid = buffer[0];
+ item->chunkUid |= (buffer[1]) << 8;
+ buffer += 2;
+
+ bool isExtra = (item->typeUid & 0x1) == 0x1;
+ if (isExtra)
+ {
+ extraItem->fragmentStart = ReadUleb128 (&buffer);
+ extraItem->fragmentEnd = ReadUleb128 (&buffer);
+ extraItem->packetUid = buffer[0];
+ extraItem->packetUid |= buffer[1] << 8;
+ extraItem->packetUid |= buffer[2] << 16;
+ extraItem->packetUid |= buffer[3] << 24;
+ buffer += 4;
+ }
+ else
+ {
+ extraItem->fragmentStart = 0;
+ extraItem->fragmentEnd = item->size;
+ extraItem->packetUid = m_packetUid;
+ }
+ NS_ASSERT (buffer <= &m_data->m_data[m_data->m_size]);
+ return buffer - &m_data->m_data[current];
+}
+
+struct PacketMetadata::Data *
+PacketMetadata::Create (uint32_t size)
+{
+ NS_DEBUG ("create size="<<size<<", max="<<m_maxSize);
+ if (size > m_maxSize)
+ {
+ m_maxSize = size;
+ }
+ while (!m_freeList.empty ())
+ {
+ struct PacketMetadata::Data *data = m_freeList.back ();
+ m_freeList.pop_back ();
+ if (data->m_size >= size)
+ {
+ NS_DEBUG ("create found size="<<data->m_size);
+ data->m_count = 1;
+ return data;
+ }
+ PacketMetadata::Deallocate (data);
+ NS_DEBUG ("create dealloc size="<<data->m_size);
+ }
+ NS_DEBUG ("create alloc size="<<m_maxSize);
+ return PacketMetadata::Allocate (m_maxSize);
+}
+
+void
+PacketMetadata::Recycle (struct PacketMetadata::Data *data)
+{
+ NS_DEBUG ("recycle size="<<data->m_size<<", list="<<m_freeList.size ());
+ NS_ASSERT (data->m_count == 0);
+ if (m_freeList.size () > 1000 ||
+ data->m_size < m_maxSize)
+ {
+ PacketMetadata::Deallocate (data);
+ }
+ else
+ {
+ m_freeList.push_back (data);
+ }
+}
+
+struct PacketMetadata::Data *
+PacketMetadata::Allocate (uint32_t n)
+{
+ uint32_t size = sizeof (struct Data);
+ if (n <= 10)
+ {
+ n = 10;
+ }
+ size += n - 10;
+ uint8_t *buf = new uint8_t [size];
+ struct PacketMetadata::Data *data = (struct PacketMetadata::Data *)buf;
+ data->m_size = n;
+ data->m_count = 1;
+ data->m_dirtyEnd = 0;
+ return data;
+}
+void
+PacketMetadata::Deallocate (struct PacketMetadata::Data *data)
+{
+ uint8_t *buf = (uint8_t *)data;
+ delete [] buf;
+}
+
+
+PacketMetadata
+PacketMetadata::CreateFragment (uint32_t start, uint32_t end) const
+{
+ PacketMetadata fragment = *this;
+ fragment.RemoveAtStart (start);
+ fragment.RemoveAtEnd (end);
+ return fragment;
+}
+
+void
+PacketMetadata::DoAddHeader (uint32_t uid, uint32_t size)
+{
+ if (!m_enable)
+ {
+ return;
+ }
+ struct PacketMetadata::SmallItem item;
+ item.next = m_head;
+ item.prev = 0xffff;
+ item.typeUid = uid;
+ item.size = size;
+ item.chunkUid = m_chunkUid;
+ m_chunkUid++;
+ uint16_t written = AddSmall (&item);
+ UpdateHead (written);
+}
+void
+PacketMetadata::DoRemoveHeader (uint32_t uid, uint32_t size)
+{
+ if (!m_enable)
+ {
+ return;
+ }
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t read = ReadItems (m_head, &item, &extraItem);
+ if ((item.typeUid & 0xfffffffe) != uid ||
+ item.size != size)
+ {
+ NS_FATAL_ERROR ("Removing unexpected header.");
+ }
+ else if (item.typeUid != uid &&
+ (extraItem.fragmentStart != 0 ||
+ extraItem.fragmentEnd != size))
+ {
+ NS_FATAL_ERROR ("Removing incomplete header.");
+ }
+ if (m_head + read == m_used)
+ {
+ m_used = m_head;
+ }
+ if (item.next == 0xffff)
+ {
+ m_head = 0xffff;
+ m_tail = 0xffff;
+ }
+ else
+ {
+ m_head = item.next;
+ }
+}
+void
+PacketMetadata::DoAddTrailer (uint32_t uid, uint32_t size)
+{
+ if (!m_enable)
+ {
+ return;
+ }
+ struct PacketMetadata::SmallItem item;
+ item.next = 0xffff;
+ item.prev = m_tail;
+ item.typeUid = uid;
+ item.size = size;
+ item.chunkUid = m_chunkUid;
+ m_chunkUid++;
+ uint16_t written = AddSmall (&item);
+ UpdateTail (written);
+}
+void
+PacketMetadata::DoRemoveTrailer (uint32_t uid, uint32_t size)
+{
+ if (!m_enable)
+ {
+ return;
+ }
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t read = ReadItems (m_tail, &item, &extraItem);
+ if ((item.typeUid & 0xfffffffe) != uid ||
+ item.size != size)
+ {
+ NS_FATAL_ERROR ("Removing unexpected trailer.");
+ }
+ else if (item.typeUid != uid &&
+ (extraItem.fragmentStart != 0 ||
+ extraItem.fragmentEnd != size))
+ {
+ NS_FATAL_ERROR ("Removing incomplete trailer.");
+ }
+ if (m_tail + read == m_used)
+ {
+ m_used = m_tail;
+ }
+ if (item.prev == 0xffff)
+ {
+ m_head = 0xffff;
+ m_tail = 0xffff;
+ }
+ else
+ {
+ m_tail = item.prev;
+ }
+}
+void
+PacketMetadata::AddAtEnd (PacketMetadata const&o)
+{
+ if (!m_enable)
+ {
+ return;
+ }
+ if (m_tail == 0xffff)
+ {
+ *this = o;
+ return;
+ }
+ NS_ASSERT (m_head != 0xffff && m_tail != 0xffff);
+
+ uint16_t lastTail;
+ lastTail = m_tail;
+ struct PacketMetadata::SmallItem lastItem;
+ PacketMetadata::ExtraItem lastExtraItem;
+ uint32_t lastTailSize = ReadItems (m_tail, &lastItem, &lastExtraItem);
+ if (m_tail + lastTailSize == m_used &&
+ m_used == m_data->m_dirtyEnd)
+ {
+ lastTailSize = m_data->m_size - m_tail;
+ }
+
+ uint16_t current = o.m_head;
+ while (current != 0xffff)
+ {
+ struct PacketMetadata::SmallItem item;
+ PacketMetadata::ExtraItem extraItem;
+ o.ReadItems (current, &item, &extraItem);
+ if (extraItem.packetUid == lastExtraItem.packetUid &&
+ item.typeUid == lastItem.typeUid &&
+ item.chunkUid == lastItem.chunkUid &&
+ item.size == lastItem.size &&
+ extraItem.fragmentStart == lastExtraItem.fragmentEnd)
+ {
+ // replace previous tail.
+ lastExtraItem.fragmentEnd = extraItem.fragmentEnd;
+ NS_ASSERT (m_tail == lastTail);
+ // XXX This call might be wrong.
+ ReplaceTail (&lastItem, &lastExtraItem, lastTailSize);
+ }
+ else
+ {
+ // append the extra items.
+ uint16_t written = AddBig (0xffff, m_tail, &item, &extraItem);
+ UpdateTail (written);
+ }
+ if (current == o.m_tail)
+ {
+ break;
+ }
+ current = item.next;
+ }
+}
+void
+PacketMetadata::AddPaddingAtEnd (uint32_t end)
+{
+ if (!m_enable)
+ {
+ return;
+ }
+}
+void
+PacketMetadata::RemoveAtStart (uint32_t start)
+{
+ if (!m_enable)
+ {
+ return;
+ }
+ NS_ASSERT (m_data != 0);
+ uint32_t leftToRemove = start;
+ uint16_t current = m_head;
+ while (current != 0xffff && leftToRemove > 0)
+ {
+ struct PacketMetadata::SmallItem item;
+ PacketMetadata::ExtraItem extraItem;
+ ReadItems (current, &item, &extraItem);
+ uint32_t itemRealSize = extraItem.fragmentEnd - extraItem.fragmentStart;
+ if (itemRealSize <= leftToRemove)
+ {
+ // remove from list.
+ m_head = item.next;
+ leftToRemove -= itemRealSize;
+ }
+ else
+ {
+ // fragment the list item.
+ PacketMetadata fragment (m_packetUid, 0);
+ extraItem.fragmentStart += leftToRemove;
+ leftToRemove = 0;
+ uint16_t written = fragment.AddBig (0xffff, fragment.m_tail,
+ &item, &extraItem);
+ fragment.UpdateTail (written);
+ current = item.next;
+ while (current != 0xffff)
+ {
+ ReadItems (current, &item, &extraItem);
+ written = fragment.AddBig (0xffff, fragment.m_tail,
+ &item, &extraItem);
+ fragment.UpdateTail (written);
+ if (current == m_tail)
+ {
+ break;
+ }
+ current = item.next;
+ }
+ *this = fragment;
+ }
+ NS_ASSERT (item.size >= extraItem.fragmentEnd - extraItem.fragmentStart &&
+ extraItem.fragmentStart <= extraItem.fragmentEnd);
+ if (current == m_tail)
+ {
+ break;
+ }
+ current = item.next;
+ }
+ NS_ASSERT (leftToRemove == 0);
+}
+void
+PacketMetadata::RemoveAtEnd (uint32_t end)
+{
+ if (!m_enable)
+ {
+ return;
+ }
+ NS_ASSERT (m_data != 0);
+
+ uint32_t leftToRemove = end;
+ uint16_t current = m_tail;
+ while (current != 0xffff && leftToRemove > 0)
+ {
+ struct PacketMetadata::SmallItem item;
+ PacketMetadata::ExtraItem extraItem;
+ ReadItems (current, &item, &extraItem);
+ uint32_t itemRealSize = extraItem.fragmentEnd - extraItem.fragmentStart;
+ if (itemRealSize <= leftToRemove)
+ {
+ // remove from list.
+ m_tail = item.prev;
+ leftToRemove -= itemRealSize;
+ }
+ else
+ {
+ // fragment the list item.
+ PacketMetadata fragment (m_packetUid, 0);
+ NS_ASSERT (extraItem.fragmentEnd > leftToRemove);
+ extraItem.fragmentEnd -= leftToRemove;
+ leftToRemove = 0;
+ uint16_t written = fragment.AddBig (fragment.m_head, 0xffff,
+ &item, &extraItem);
+ fragment.UpdateHead (written);
+ current = item.prev;
+ while (current != 0xffff)
+ {
+ ReadItems (current, &item, &extraItem);
+ written = fragment.AddBig (fragment.m_head, 0xffff,
+ &item, &extraItem);
+ fragment.UpdateHead (written);
+ if (current == m_head)
+ {
+ break;
+ }
+ current = item.prev;
+ }
+ *this = fragment;
+ }
+ NS_ASSERT (item.size >= extraItem.fragmentEnd - extraItem.fragmentStart &&
+ extraItem.fragmentStart <= extraItem.fragmentEnd);
+ if (current == m_head)
+ {
+ break;
+ }
+ current = item.prev;
+ }
+ NS_ASSERT (leftToRemove == 0);
+}
+
+void
+PacketMetadata::PrintDefault (std::ostream &os, Buffer buffer) const
+{
+ Print (os, buffer, PacketPrinter::GetDefault ());
+}
+
+uint32_t
+PacketMetadata::DoPrint (const struct PacketMetadata::SmallItem *item,
+ const struct PacketMetadata::ExtraItem *extraItem,
+ Buffer data, uint32_t offset, const PacketPrinter &printer,
+ std::ostream &os) const
+{
+ uint32_t uid = item->typeUid & 0xfffffffe;
+ if (uid == 0)
+ {
+ // payload.
+ printer.PrintPayload (os, extraItem->packetUid, item->size,
+ extraItem->fragmentStart,
+ item->size - extraItem->fragmentEnd);
+ }
+ else if (extraItem->fragmentStart != 0 ||
+ extraItem->fragmentEnd != item->size)
+ {
+ printer.PrintChunkFragment (uid, os, extraItem->packetUid, item->size,
+ extraItem->fragmentStart,
+ item->size - extraItem->fragmentEnd);
+ }
+ else if (PacketPrinter::IsHeader (uid))
+ {
+ ns3::Buffer::Iterator j = data.Begin ();
+ j.Next (offset);
+ printer.PrintChunk (uid, j, os, extraItem->packetUid, item->size);
+ }
+ else if (PacketPrinter::IsTrailer (uid))
+ {
+ ns3::Buffer::Iterator j = data.End ();
+ j.Prev (data.GetSize () - (offset + item->size));
+ printer.PrintChunk (uid, j, os, extraItem->packetUid, item->size);
+ }
+ else
+ {
+ NS_ASSERT (false);
+ }
+ return extraItem->fragmentEnd - extraItem->fragmentStart;
+}
+
+uint32_t
+PacketMetadata::GetTotalSize (void) const
+{
+ uint32_t totalSize = 0;
+ uint16_t current = m_head;
+ uint16_t tail = m_tail;
+ while (current != 0xffff)
+ {
+ struct PacketMetadata::SmallItem item;
+ PacketMetadata::ExtraItem extraItem;
+ ReadItems (current, &item, &extraItem);
+ totalSize += extraItem.fragmentEnd - extraItem.fragmentStart;
+ if (current == tail)
+ {
+ break;
+ }
+ NS_ASSERT (current != item.next);
+ current = item.next;
+ }
+ return totalSize;
+}
+
+uint32_t
+PacketMetadata::GetUid (void) const
+{
+ return m_packetUid;
+}
+
+void
+PacketMetadata::Print (std::ostream &os, Buffer data, const PacketPrinter &printer) const
+{
+ if (!m_enable)
+ {
+ return;
+ }
+ NS_ASSERT (m_data != 0);
+ NS_ASSERT (GetTotalSize () == data.GetSize ());
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ if (printer.m_forward)
+ {
+ uint32_t current = m_head;
+ uint32_t offset = 0;
+ while (current != 0xffff)
+ {
+ ReadItems (current, &item, &extraItem);
+ uint32_t realSize = DoPrint (&item, &extraItem, data, offset, printer, os);
+ offset += realSize;
+ if (current == m_tail)
+ {
+ break;
+ }
+ if (item.next != 0xffff)
+ {
+ os << printer.m_separator;
+ }
+ NS_ASSERT (current != item.next);
+ current = item.next;
+ }
+ }
+ else
+ {
+ uint32_t current = m_tail;
+ uint32_t offset = data.GetSize ();
+ while (current != 0xffff)
+ {
+ ReadItems (current, &item, &extraItem);
+ uint32_t realSize = DoPrint (&item, &extraItem, data, offset - item.size, printer, os);
+ offset -= realSize;
+ if (current == m_head)
+ {
+ break;
+ }
+ if (item.prev != 0xffff)
+ {
+ os << printer.m_separator;
+ }
+ NS_ASSERT (current != item.prev);
+ current = item.prev;
+ }
+ }
+}
+
+
+
+}; // namespace ns3
+
+#include <stdarg.h>
+#include <iostream>
+#include <sstream>
+#include "ns3/test.h"
+#include "header.h"
+#include "trailer.h"
+#include "packet.h"
+
+namespace ns3 {
+
+template <int N>
+class HistoryHeader : public Header
+{
+public:
+ HistoryHeader ();
+ bool IsOk (void) const;
+private:
+ virtual std::string DoGetName (void) const;
+ virtual void PrintTo (std::ostream &os) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void SerializeTo (Buffer::Iterator start) const;
+ virtual uint32_t DeserializeFrom (Buffer::Iterator start);
+ bool m_ok;
+};
+
+template <int N>
+HistoryHeader<N>::HistoryHeader ()
+ : m_ok (false)
+{}
+
+template <int N>
+bool
+HistoryHeader<N>::IsOk (void) const
+{
+ return m_ok;
+}
+
+template <int N>
+std::string
+HistoryHeader<N>::DoGetName (void) const
+{
+ std::ostringstream oss;
+ oss << N;
+ return oss.str ();
+}
+
+template <int N>
+void
+HistoryHeader<N>::PrintTo (std::ostream &os) const
+{
+ NS_ASSERT (false);
+}
+template <int N>
+uint32_t
+HistoryHeader<N>::GetSerializedSize (void) const
+{
+ return N;
+}
+template <int N>
+void
+HistoryHeader<N>::SerializeTo (Buffer::Iterator start) const
+{
+ start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryHeader<N>::DeserializeFrom (Buffer::Iterator start)
+{
+ m_ok = true;
+ for (int i = 0; i < N; i++)
+ {
+ if (start.ReadU8 () != N)
+ {
+ m_ok = false;
+ }
+ }
+ return N;
+}
+
+template <int N>
+class HistoryTrailer : public Trailer
+{
+public:
+ HistoryTrailer ();
+ bool IsOk (void) const;
+private:
+ virtual std::string DoGetName (void) const;
+ virtual void PrintTo (std::ostream &os) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void SerializeTo (Buffer::Iterator start) const;
+ virtual uint32_t DeserializeFrom (Buffer::Iterator start);
+ bool m_ok;
+};
+
+template <int N>
+HistoryTrailer<N>::HistoryTrailer ()
+ : m_ok (false)
+{}
+
+template <int N>
+bool
+HistoryTrailer<N>::IsOk (void) const
+{
+ return m_ok;
+}
+
+template <int N>
+std::string
+HistoryTrailer<N>::DoGetName (void) const
+{
+ std::ostringstream oss;
+ oss << N;
+ return oss.str ();
+}
+template <int N>
+void
+HistoryTrailer<N>::PrintTo (std::ostream &os) const
+{
+ NS_ASSERT (false);
+}
+template <int N>
+uint32_t
+HistoryTrailer<N>::GetSerializedSize (void) const
+{
+ return N;
+}
+template <int N>
+void
+HistoryTrailer<N>::SerializeTo (Buffer::Iterator start) const
+{
+ start.Prev (N);
+ start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryTrailer<N>::DeserializeFrom (Buffer::Iterator start)
+{
+ m_ok = true;
+ start.Prev (N);
+ for (int i = 0; i < N; i++)
+ {
+ if (start.ReadU8 () != N)
+ {
+ m_ok = false;
+ }
+ }
+ return N;
+}
+
+
+
+class PacketMetadataTest : public Test {
+public:
+ PacketMetadataTest ();
+ virtual ~PacketMetadataTest ();
+ bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...);
+ virtual bool RunTests (void);
+private:
+ template <int N>
+ void PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryHeader<N> *header);
+ template <int N>
+ void PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryTrailer<N> *trailer);
+ void PrintFragment (std::ostream &os,uint32_t packetUid,
+ uint32_t size,std::string & name,
+ struct PacketPrinter::FragmentInformation info);
+ void PrintDefault (std::ostream& os,uint32_t packetUid,
+ uint32_t size,std::string& name,
+ struct PacketPrinter::FragmentInformation info);
+ void PrintPayload (std::ostream &os,uint32_t packetUid,
+ uint32_t size,
+ struct PacketPrinter::FragmentInformation info);
+ template <int N>
+ void RegisterHeader (void);
+ template <int N>
+ void RegisterTrailer (void);
+ void CleanupPrints (void);
+ bool Check (const char *file, int line, std::list<int> expected);
+
+
+ bool m_headerError;
+ bool m_trailerError;
+ std::list<int> m_prints;
+ PacketPrinter m_printer;
+};
+
+PacketMetadataTest::PacketMetadataTest ()
+ : Test ("PacketMetadata")
+{
+ m_printer.AddPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this));
+ m_printer.AddDefaultPrinter (MakeCallback (&PacketMetadataTest::PrintDefault, this));
+}
+
+PacketMetadataTest::~PacketMetadataTest ()
+{}
+
+template <int N>
+void
+PacketMetadataTest::RegisterHeader (void)
+{
+ static bool registered = false;
+ if (!registered)
+ {
+ m_printer.AddHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader<N>, this),
+ MakeCallback (&PacketMetadataTest::PrintFragment, this));
+ registered = true;
+ }
+}
+
+template <int N>
+void
+PacketMetadataTest::RegisterTrailer (void)
+{
+ static bool registered = false;
+ if (!registered)
+ {
+ m_printer.AddTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer<N>, this),
+ MakeCallback (&PacketMetadataTest::PrintFragment, this));
+ registered = true;
+ }
+}
+
+
+template <int N>
+void
+PacketMetadataTest::PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size,
+ const HistoryHeader<N> *header)
+{
+ if (!header->IsOk ())
+ {
+ m_headerError = true;
+ }
+ m_prints.push_back (N);
+}
+
+template <int N>
+void
+PacketMetadataTest::PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size,
+ const HistoryTrailer<N> *trailer)
+{
+ if (!trailer->IsOk ())
+ {
+ m_trailerError = true;
+ }
+ m_prints.push_back (N);
+}
+void
+PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid,
+ uint32_t size,std::string & name,
+ struct PacketPrinter::FragmentInformation info)
+{
+ m_prints.push_back (size - (info.end + info.start));
+}
+void
+PacketMetadataTest::PrintDefault (std::ostream& os,uint32_t packetUid,
+ uint32_t size,std::string& name,
+ struct PacketPrinter::FragmentInformation info)
+{
+ NS_ASSERT (false);
+}
+void
+PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid,
+ uint32_t size,
+ struct PacketPrinter::FragmentInformation info)
+{
+ m_prints.push_back (size - (info.end + info.start));
+}
+
+
+void
+PacketMetadataTest::CleanupPrints (void)
+{
+ m_prints.clear ();
+}
+
+bool
+PacketMetadataTest::Check (const char *file, int line, std::list<int> expected)
+{
+ if (m_headerError)
+ {
+ std::cout << "PacketMetadata header error. file=" << file
+ << ", line=" << line << std::endl;
+ return false;
+ }
+ if (m_trailerError)
+ {
+ std::cout << "PacketMetadata trailer error. file=" << file
+ << ", line=" << line << std::endl;
+ return false;
+ }
+ if (expected.size () != m_prints.size ())
+ {
+ goto error;
+ }
+ for (std::list<int>::iterator i = m_prints.begin (),
+ j = expected.begin ();
+ i != m_prints.end (); i++, j++)
+ {
+ NS_ASSERT (j != expected.end ());
+ if (*j != *i)
+ {
+ goto error;
+ }
+ }
+ return true;
+ error:
+ std::cout << "PacketMetadata error. file="<< file
+ << ", line=" << line << ", got:\"";
+ for (std::list<int>::iterator i = m_prints.begin ();
+ i != m_prints.end (); i++)
+ {
+ std::cout << *i << ", ";
+ }
+ std::cout << "\", expected: \"";
+ for (std::list<int>::iterator j = expected.begin ();
+ j != expected.end (); j++)
+ {
+ std::cout << *j << ", ";
+ }
+ std::cout << "\"" << std::endl;
+ return false;
+}
+
+bool
+PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...)
+{
+ m_headerError = false;
+ m_trailerError = false;
+ std::list<int> expected;
+ va_list ap;
+ va_start (ap, n);
+ for (uint32_t j = 0; j < n; j++)
+ {
+ int v = va_arg (ap, int);
+ expected.push_back (v);
+ }
+ va_end (ap);
+
+ m_printer.PrintForward ();
+ p.Print (std::cerr, m_printer);
+ bool ok = Check (file, line, expected);
+ CleanupPrints ();
+ if (!ok)
+ {
+ return false;
+ }
+
+ m_printer.PrintBackward ();
+ p.Print (std::cerr, m_printer);
+ expected.reverse ();
+ ok = Check (file, line, expected);
+ CleanupPrints ();
+ return ok;
+}
+
+#define ADD_HEADER(p, n) \
+ { \
+ HistoryHeader<n> header; \
+ RegisterHeader<n> (); \
+ p.AddHeader (header); \
+ }
+#define ADD_TRAILER(p, n) \
+ { \
+ HistoryTrailer<n> trailer; \
+ RegisterTrailer<n> (); \
+ p.AddTrailer (trailer); \
+ }
+#define REM_HEADER(p, n) \
+ { \
+ HistoryHeader<n> header; \
+ RegisterHeader<n> (); \
+ p.RemoveHeader (header); \
+ }
+#define REM_TRAILER(p, n) \
+ { \
+ HistoryTrailer<n> trailer; \
+ RegisterTrailer<n> (); \
+ p.RemoveTrailer (trailer); \
+ }
+#define CHECK_HISTORY(p, ...) \
+ { \
+ if (!CheckHistory (p, __FILE__, \
+ __LINE__, __VA_ARGS__)) \
+ { \
+ ok = false; \
+ } \
+ }
+
+bool
+PacketMetadataTest::RunTests (void)
+{
+ bool ok = true;
+
+ PacketMetadata::Enable ();
+
+ Packet p = Packet (0);
+ Packet p1 = Packet (0);
+
+ p = Packet (10);
+ ADD_TRAILER (p, 100);
+ CHECK_HISTORY (p, 2, 10, 100);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ ADD_HEADER (p, 5);
+ CHECK_HISTORY (p, 5,
+ 5, 3, 2, 1, 10);
+ ADD_HEADER (p, 6);
+ CHECK_HISTORY (p, 6,
+ 6, 5, 3, 2, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ REM_HEADER (p, 3);
+ CHECK_HISTORY (p, 3,
+ 2, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ REM_HEADER (p, 3);
+ REM_HEADER (p, 2);
+ CHECK_HISTORY (p, 2,
+ 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ REM_HEADER (p, 3);
+ REM_HEADER (p, 2);
+ REM_HEADER (p, 1);
+ CHECK_HISTORY (p, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ p1 = p;
+ REM_HEADER (p1, 3);
+ REM_HEADER (p1, 2);
+ REM_HEADER (p1, 1);
+ CHECK_HISTORY (p1, 1, 10);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ ADD_HEADER (p1, 1);
+ ADD_HEADER (p1, 2);
+ CHECK_HISTORY (p1, 3,
+ 2, 1, 10);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ ADD_HEADER (p, 3);
+ CHECK_HISTORY (p, 5,
+ 3, 3, 2, 1, 10);
+ ADD_TRAILER (p, 4);
+ CHECK_HISTORY (p, 6,
+ 3, 3, 2, 1, 10, 4);
+ ADD_TRAILER (p, 5);
+ CHECK_HISTORY (p, 7,
+ 3, 3, 2, 1, 10, 4, 5);
+ REM_HEADER (p, 3);
+ CHECK_HISTORY (p, 6,
+ 3, 2, 1, 10, 4, 5);
+ REM_TRAILER (p, 5);
+ CHECK_HISTORY (p, 5,
+ 3, 2, 1, 10, 4);
+ p1 = p;
+ REM_TRAILER (p, 4);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ CHECK_HISTORY (p1, 5,
+ 3, 2, 1, 10, 4);
+ p1.RemoveAtStart (3);
+ CHECK_HISTORY (p1, 4,
+ 2, 1, 10, 4);
+ p1.RemoveAtStart (1);
+ CHECK_HISTORY (p1, 4,
+ 1, 1, 10, 4);
+ p1.RemoveAtStart (1);
+ CHECK_HISTORY (p1, 3,
+ 1, 10, 4);
+ p1.RemoveAtEnd (4);
+ CHECK_HISTORY (p1, 2,
+ 1, 10);
+ p1.RemoveAtStart (1);
+ CHECK_HISTORY (p1, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 8);
+ ADD_TRAILER (p, 8);
+ ADD_TRAILER (p, 8);
+ p.RemoveAtStart (8+10+8);
+ CHECK_HISTORY (p, 1, 8);
+
+ p = Packet (10);
+ ADD_HEADER (p, 10);
+ ADD_HEADER (p, 8);
+ ADD_TRAILER (p, 6);
+ ADD_TRAILER (p, 7);
+ ADD_TRAILER (p, 9);
+ p.RemoveAtStart (5);
+ p.RemoveAtEnd (12);
+ CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4);
+
+ p = Packet (10);
+ ADD_HEADER (p, 10);
+ ADD_TRAILER (p, 6);
+ p.RemoveAtEnd (18);
+ ADD_TRAILER (p, 5);
+ ADD_HEADER (p, 3);
+ CHECK_HISTORY (p, 3, 3, 8, 5);
+ p.RemoveAtStart (12);
+ CHECK_HISTORY (p, 1, 4);
+ p.RemoveAtEnd (2);
+ CHECK_HISTORY (p, 1, 2);
+ ADD_HEADER (p, 10);
+ CHECK_HISTORY (p, 2, 10, 2);
+ p.RemoveAtEnd (5);
+ CHECK_HISTORY (p, 1, 7);
+
+ Packet p2 = Packet (0);
+ Packet p3 = Packet (0);
+
+ p = Packet (40);
+ ADD_HEADER (p, 5);
+ ADD_HEADER (p, 8);
+ CHECK_HISTORY (p, 3, 8, 5, 40);
+ p1 = p.CreateFragment (0, 5);
+ p2 = p.CreateFragment (5, 5);
+ p3 = p.CreateFragment (10, 43);
+ CHECK_HISTORY (p1, 1, 5);
+ CHECK_HISTORY (p2, 2, 3, 2);
+ CHECK_HISTORY (p3, 2, 3, 40);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 8, 2);
+ CHECK_HISTORY (p2, 2, 3, 2);
+ p1.AddAtEnd (p3);
+ CHECK_HISTORY (p1, 3, 8, 5, 40);
+ CHECK_HISTORY (p2, 2, 3, 2);
+ CHECK_HISTORY (p3, 2, 3, 40);
+ p1 = p.CreateFragment (0, 5);
+ CHECK_HISTORY (p1, 1, 5);
+
+ p3 = Packet (50);
+ ADD_HEADER (p3, 8);
+ CHECK_HISTORY (p3, 2, 8, 50);
+ CHECK_HISTORY (p1, 1, 5);
+ p1.AddAtEnd (p3);
+ CHECK_HISTORY (p1, 3, 5, 8, 50);
+ ADD_HEADER (p1, 5);
+ CHECK_HISTORY (p1, 4, 5, 5, 8, 50);
+ ADD_TRAILER (p1, 2);
+ CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2);
+ REM_HEADER (p1, 5);
+ CHECK_HISTORY (p1, 4, 5, 8, 50, 2);
+ p1.RemoveAtEnd (60);
+ CHECK_HISTORY (p1, 1, 5);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 8, 2);
+ CHECK_HISTORY (p2, 2, 3, 2);
+
+ p3 = Packet (40);
+ ADD_HEADER (p3, 5);
+ ADD_HEADER (p3, 5);
+ CHECK_HISTORY (p3, 3, 5, 5, 40);
+ p1 = p3.CreateFragment (0, 5);
+ p2 = p3.CreateFragment (5, 5);
+ CHECK_HISTORY (p1, 1, 5);
+ CHECK_HISTORY (p2, 1, 5);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 5, 5);
+
+ p = Packet (0);
+ CHECK_HISTORY (p, 0);
+
+ p3 = Packet (0);
+ ADD_HEADER (p3, 5);
+ ADD_HEADER (p3, 5);
+ CHECK_HISTORY (p3, 2, 5, 5);
+ p1 = p3.CreateFragment (0, 4);
+ p2 = p3.CreateFragment (9, 1);
+ CHECK_HISTORY (p1, 1, 4);
+ CHECK_HISTORY (p2, 1, 1);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 4, 1);
+
+
+ p = Packet (2000);
+ CHECK_HISTORY (p, 1, 2000);
+
+ p = Packet ();
+ ADD_TRAILER (p, 10);
+ ADD_HEADER (p, 5);
+ p1 = p.CreateFragment (0, 8);
+ p2 = p.CreateFragment (8, 7);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p, 2, 5, 10);
+
+ p = Packet ();
+ ADD_TRAILER (p, 10);
+ REM_TRAILER (p, 10);
+ ADD_TRAILER (p, 10);
+ CHECK_HISTORY (p, 1, 10);
+
+ p = Packet ();
+ ADD_HEADER (p, 10);
+ REM_HEADER (p, 10);
+ ADD_HEADER (p, 10);
+ CHECK_HISTORY (p, 1, 10);
+
+ return ok;
+}
+
+static PacketMetadataTest g_packetHistoryTest;
+
+}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata.h Fri Jul 06 14:39:59 2007 -0700
@@ -0,0 +1,335 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_METADATA_H
+#define PACKET_METADATA_H
+
+#include <stdint.h>
+#include <vector>
+#include "ns3/callback.h"
+#include "ns3/assert.h"
+#include "packet-printer.h"
+
+namespace ns3 {
+
+class Chunk;
+class Buffer;
+
+/**
+ * \internal
+ * \brief handle packet metadata about packet headers and trailers
+ *
+ * This class is used by the Packet class to record every operation
+ * performed on the packet's buffer. This class also provides
+ * an implementation of the Packet::Print methods which uses
+ * the metadata to analyse the content of the packet's buffer.
+ *
+ * To achieve this, this class maintains a linked list of so-called
+ * "items", each of which represents a header or a trailer, or
+ * payload, or a fragment of any of these. Each item contains a "next"
+ * and a "prev" field which point to the next and previous entries
+ * in the linked list. The PacketMetadata class maintains a pair
+ * of pointers to the head and the tail of the linked list.
+ *
+ * Each entry in the list also maintains:
+ * - its native size (the size it had when it was first added
+ * to the packet)
+ * - its type: identifies what kind of header, what kind of trailer,
+ * if it is payload or not
+ * - the uid of the packet to which it was first added
+ * - the start and end of the area represented by a fragment
+ * if it is one.
+ *
+ * This linked list is flattened in a byte buffer stored in
+ * struct PacketMetadata::Data. Each entry of the linked list is
+ * identified by an offset which identifies the first byte of the
+ * entry from the start of the data buffer. The size of this data
+ * buffer is 2^16-1 bytes maximum which somewhat limits the number
+ * of entries which can be stored in this linked list but it is
+ * quite unlikely to hit this limit in practice.
+ *
+ * Each item of the linked list is a variable-sized byte buffer
+ * made of a number of fields. Some of these fields are stored
+ * as fixed-size 32 bit integers, others as fixed-size 16 bit
+ * integers, and some others as variable-size 32-bit integers.
+ * The variable-size 32 bit integers are stored using the uleb128
+ * encoding.
+ */
+class PacketMetadata {
+public:
+ static void Enable (void);
+ static void SetOptOne (bool optOne);
+
+ inline PacketMetadata (uint32_t uid, uint32_t size);
+ inline PacketMetadata (PacketMetadata const &o);
+ inline PacketMetadata &operator = (PacketMetadata const& o);
+ inline ~PacketMetadata ();
+
+ template <typename T>
+ void AddHeader (T const &header, uint32_t size);
+ template <typename T>
+ void RemoveHeader (T const &header, uint32_t size);
+
+ template <typename T>
+ void AddTrailer (T const &trailer, uint32_t size);
+ template <typename T>
+ void RemoveTrailer (T const &trailer, uint32_t size);
+
+ PacketMetadata CreateFragment (uint32_t start, uint32_t end) const;
+ void AddAtEnd (PacketMetadata const&o);
+ void AddPaddingAtEnd (uint32_t end);
+ void RemoveAtStart (uint32_t start);
+ void RemoveAtEnd (uint32_t end);
+
+ uint32_t GetUid (void) const;
+
+ void PrintDefault (std::ostream &os, Buffer buffer) const;
+ void Print (std::ostream &os, Buffer buffer, PacketPrinter const &printer) const;
+
+ static void PrintStats (void);
+
+private:
+ struct Data {
+ /* number of references to this struct Data instance. */
+ uint16_t m_count;
+ /* size (in bytes) of m_data buffer below */
+ uint16_t m_size;
+ /* max of the m_used field over all objects which
+ * reference this struct Data instance */
+ uint16_t m_dirtyEnd;
+ /* variable-sized buffer of bytes */
+ uint8_t m_data[10];
+ };
+ /* Note that since the next and prev fields are 16 bit integers
+ and since the value 0xffff is reserved to identify the
+ fact that the end or the start of the list is reached,
+ only a limited number of elements can be stored in
+ a m_data byte buffer.
+ */
+ struct SmallItem {
+ /* offset (in bytes) from start of m_data buffer
+ to next element in linked list. value is 0xffff
+ if next element does not exist.
+ stored as a fixed-size 16 bit integer.
+ */
+ uint16_t next;
+ /* offset (in bytes) from start of m_data buffer
+ to previous element in linked list. value is 0xffff
+ if previous element does not exist.
+ stored as a fixed-size 16 bit integer.
+ */
+ uint16_t prev;
+ /* the high 31 bits of this field identify the
+ type of the header or trailer represented by
+ this item: the value zero represents payload.
+ If the low bit of this uid is one, an ExtraItem
+ structure follows this SmallItem structure.
+ stored as a variable-size 32 bit integer.
+ */
+ uint32_t typeUid;
+ /* the size (in bytes) of the header or trailer represented
+ by this element.
+ stored as a variable-size 32 bit integer.
+ */
+ uint32_t size;
+ /* this field tries to uniquely identify each header or
+ trailer _instance_ while the typeUid field uniquely
+ identifies each header or trailer _type_. This field
+ is used to test whether two items are equal in the sense
+ that they represent the same header or trailer instance.
+ That equality test is based on the typeUid and chunkUid
+ fields so, the likelyhood that two header instances
+ share the same chunkUid _and_ typeUid is very small
+ unless they are really representations of the same header
+ instance.
+ stored as a fixed-size 16 bit integer.
+ */
+ uint16_t chunkUid;
+ };
+ struct ExtraItem {
+ /* offset (in bytes) from start of original header to
+ the start of the fragment still present.
+ stored as a variable-size 32 bit integer.
+ */
+ uint32_t fragmentStart;
+ /* offset (in bytes) from start of original header to
+ the end of the fragment still present.
+ stored as a variable-size 32 bit integer.
+ */
+ uint32_t fragmentEnd;
+ /* the packetUid of the packet in which this header or trailer
+ was first added. It could be different from the m_packetUid
+ field if the user has aggregated multiple packets into one.
+ stored as a fixed-size 32 bit integer.
+ */
+ uint32_t packetUid;
+ };
+
+ typedef std::vector<struct Data *> DataFreeList;
+
+ PacketMetadata ();
+ void DoAddHeader (uint32_t uid, uint32_t size);
+ void DoRemoveHeader (uint32_t uid, uint32_t size);
+ void DoAddTrailer (uint32_t uid, uint32_t size);
+ void DoRemoveTrailer (uint32_t uid, uint32_t size);
+
+ inline uint16_t AddSmall (const PacketMetadata::SmallItem *item);
+ uint16_t AddBig (uint32_t head, uint32_t tail,
+ const PacketMetadata::SmallItem *item,
+ const PacketMetadata::ExtraItem *extraItem);
+ void ReplaceTail (PacketMetadata::SmallItem *item,
+ PacketMetadata::ExtraItem *extraItem,
+ uint32_t available);
+ inline void UpdateHead (uint16_t written);
+ inline void UpdateTail (uint16_t written);
+ uint32_t GetUleb128Size (uint32_t value) const;
+ uint32_t ReadUleb128 (const uint8_t **pBuffer) const;
+ inline void Append16 (uint16_t value, uint8_t *buffer);
+ inline bool TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end);
+ inline bool TryToAppendFast (uint32_t value, uint8_t **pBuffer, uint8_t *end);
+ inline bool TryToAppend32 (uint32_t value, uint8_t **pBuffer, uint8_t *end);
+ inline bool TryToAppend16 (uint16_t value, uint8_t **pBuffer, uint8_t *end);
+ void AppendValue (uint32_t value, uint8_t *buffer);
+ void AppendValueExtra (uint32_t value, uint8_t *buffer);
+ inline void Reserve (uint32_t n);
+ void ReserveCopy (uint32_t n);
+ uint32_t DoPrint (const struct PacketMetadata::SmallItem *item,
+ const struct PacketMetadata::ExtraItem *extraItem,
+ Buffer data, uint32_t offset, const PacketPrinter &printer,
+ std::ostream &os) const;
+ uint32_t GetTotalSize (void) const;
+ uint32_t ReadItems (uint16_t current,
+ struct PacketMetadata::SmallItem *item,
+ struct PacketMetadata::ExtraItem *extraItem) const;
+
+
+ static struct PacketMetadata::Data *Create (uint32_t size);
+ static void Recycle (struct PacketMetadata::Data *data);
+ static struct PacketMetadata::Data *Allocate (uint32_t n);
+ static void Deallocate (struct PacketMetadata::Data *data);
+
+ static DataFreeList m_freeList;
+ static bool m_enable;
+ static uint32_t m_maxSize;
+ static uint16_t m_chunkUid;
+
+ struct Data *m_data;
+ /**
+ head -(next)-> tail
+ ^ |
+ \---(prev)---|
+ */
+ uint16_t m_head;
+ uint16_t m_tail;
+ uint16_t m_used;
+ uint32_t m_packetUid;
+};
+
+}; // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void
+PacketMetadata::AddHeader (T const &header, uint32_t size)
+{
+ DoAddHeader (PacketPrinter::GetHeaderUid<T> (), size);
+}
+
+template <typename T>
+void
+PacketMetadata::RemoveHeader (T const &header, uint32_t size)
+{
+ DoRemoveHeader (PacketPrinter::GetHeaderUid<T> (), size);
+}
+template <typename T>
+void
+PacketMetadata::AddTrailer (T const &trailer, uint32_t size)
+{
+ DoAddTrailer (PacketPrinter::GetTrailerUid<T> (), size);
+}
+template <typename T>
+void
+PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size)
+{
+ DoRemoveTrailer (PacketPrinter::GetTrailerUid<T> (), size);
+}
+
+
+PacketMetadata::PacketMetadata (uint32_t uid, uint32_t size)
+ : m_data (m_data = PacketMetadata::Create (10)),
+ m_head (0xffff),
+ m_tail (0xffff),
+ m_used (0),
+ m_packetUid (uid)
+{
+ memset (m_data->m_data, 0xff, 4);
+ if (size > 0)
+ {
+ DoAddHeader (0, size);
+ }
+}
+PacketMetadata::PacketMetadata (PacketMetadata const &o)
+ : m_data (o.m_data),
+ m_head (o.m_head),
+ m_tail (o.m_tail),
+ m_used (o.m_used),
+ m_packetUid (o.m_packetUid)
+{
+ NS_ASSERT (m_data != 0);
+ m_data->m_count++;
+}
+PacketMetadata &
+PacketMetadata::operator = (PacketMetadata const& o)
+{
+ if (m_data == o.m_data)
+ {
+ // self assignment
+ return *this;
+ }
+ NS_ASSERT (m_data != 0);
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ PacketMetadata::Recycle (m_data);
+ }
+ m_data = o.m_data;
+ m_head = o.m_head;
+ m_tail = o.m_tail;
+ m_used = o.m_used;
+ m_packetUid = o.m_packetUid;
+ NS_ASSERT (m_data != 0);
+ m_data->m_count++;
+ return *this;
+}
+PacketMetadata::~PacketMetadata ()
+{
+ NS_ASSERT (m_data != 0);
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ PacketMetadata::Recycle (m_data);
+ }
+}
+
+}; // namespace ns3
+
+
+#endif /* PACKET_METADATA_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-printer.cc Fri Jul 06 14:39:59 2007 -0700
@@ -0,0 +1,235 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "packet-printer.h"
+
+namespace ns3 {
+
+PacketPrinter::PacketPrinter ()
+ : m_forward (true),
+ m_separator ("")
+{}
+
+void
+PacketPrinter::PrintForward (void)
+{
+ m_forward = true;
+}
+void
+PacketPrinter::PrintBackward (void)
+{
+ m_forward = false;
+}
+void
+PacketPrinter::SetSeparator (std::string separator)
+{
+ m_separator = separator;
+}
+void
+PacketPrinter::AddPayloadPrinter (PayloadPrinter printer)
+{
+ m_payloadPrinter = printer;
+}
+void
+PacketPrinter::AddDefaultPrinter (DefaultPrinter printer)
+{
+ m_defaultPrinter = printer;
+}
+
+PacketPrinter::RegisteredChunks *
+PacketPrinter::GetRegisteredChunks (void)
+{
+ static RegisteredChunks registeredChunks;
+ return ®isteredChunks;
+}
+
+PacketPrinter
+PacketPrinter::GetDefault (void)
+{
+ return *(PacketPrinter::PeekDefault ());
+}
+PacketPrinter *
+PacketPrinter::PeekDefault (void)
+{
+ static PacketPrinter *tmp = PacketPrinter::CreateStaticDefault ();
+ return tmp;
+}
+PacketPrinter *
+PacketPrinter::CreateStaticDefault (void)
+{
+ static PacketPrinter tmp;
+ tmp.PrintForward ();
+ tmp.AddPayloadPrinter (MakeCallback (&PacketPrinter::DoDefaultPrintPayload));
+ tmp.SetSeparator (" ");
+ return &tmp;
+}
+
+
+void
+PacketPrinter::PrintChunk (uint32_t chunkUid,
+ Buffer::Iterator start,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size) const
+{
+ RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
+ NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
+ for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
+ {
+ if (i->m_chunkUid == chunkUid)
+ {
+ DoPrintCallback cb = (*registeredChunks)[chunkUid/2-1].printCallback;
+ cb (i->m_printer, start, os, packetUid, size);
+ return;
+ }
+ }
+ DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
+ std::string name = cb ();
+ struct PacketPrinter::FragmentInformation info;
+ info.start = 0;
+ info.end = 0;
+ if (!m_defaultPrinter.IsNull ())
+ {
+ m_defaultPrinter (os, packetUid, size, name, info);
+ }
+}
+void
+PacketPrinter::PrintChunkFragment (uint32_t chunkUid,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size,
+ uint32_t fragmentStart,
+ uint32_t fragmentEnd) const
+{
+ RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
+ NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
+ DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
+ std::string name = cb ();
+ struct PacketPrinter::FragmentInformation info;
+ info.start = fragmentStart;
+ info.end = fragmentEnd;
+ for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
+ {
+ if (i->m_chunkUid == chunkUid)
+ {
+ i->m_fragmentPrinter (os, packetUid, size, name, info);
+ return;
+ }
+ }
+ if (!m_defaultPrinter.IsNull ())
+ {
+ m_defaultPrinter (os, packetUid, size, name, info);
+ }
+}
+void
+PacketPrinter::PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
+ uint32_t fragmentStart, uint32_t fragmentEnd) const
+{
+ struct PacketPrinter::FragmentInformation info;
+ info.start = fragmentStart;
+ info.end = fragmentEnd;
+ if (!m_payloadPrinter.IsNull ())
+ {
+ m_payloadPrinter (os, packetUid, size, info);
+ }
+}
+
+void
+PacketPrinter::DoDefaultPrintPayload (std::ostream & os,
+ uint32_t packetUid,
+ uint32_t size,
+ struct PacketPrinter::FragmentInformation info)
+{
+ os << "DATA ("
+ << "length " << size - (info.end + info.start);
+ if (info.start != 0 || info.end != 0)
+ {
+ os << " "
+ << "trim_start " << info.start << " "
+ << "trim_end " << info.end;
+ }
+ os << ")";
+}
+
+void
+PacketPrinter::DoDefaultPrintDefault (std::ostream & os,
+ uint32_t packetUid,
+ uint32_t size,
+ std::string &name,
+ struct PacketPrinter::FragmentInformation info)
+{
+ NS_ASSERT_MSG (false, "This should never happen because we provide a printer for _all_ chunk types.");
+}
+
+void
+PacketPrinter::DoDefaultPrintFragment (std::ostream & os,
+ uint32_t packetUid,
+ uint32_t size,
+ std::string &name,
+ struct PacketPrinter::FragmentInformation info)
+{
+ NS_ASSERT (info.start != 0 || info.end != 0);
+ os << name << " "
+ << "("
+ << "length " << size - (info.end + info.start) << " "
+ << "trim_start " << info.start << " "
+ << "trim_end " << info.end
+ << ")"
+ ;
+}
+
+void
+PacketPrinter::DoAddPrinter (uint32_t uid,
+ Ptr<CallbackImplBase> printer,
+ Callback<void,
+ std::ostream &,
+ uint32_t,
+ uint32_t,
+ std::string &,
+ struct PacketPrinter::FragmentInformation> fragmentPrinter)
+{
+ struct PacketPrinter::Printer p;
+ p.m_chunkUid = uid;
+ p.m_printer = printer;
+ p.m_fragmentPrinter = fragmentPrinter;
+ m_printerList.push_back (p);
+}
+
+bool
+PacketPrinter::IsTrailer (uint32_t uid)
+{
+ RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
+ NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
+ bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
+ return !isHeader;
+}
+bool
+PacketPrinter::IsHeader (uint32_t uid)
+{
+ RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
+ NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
+ bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
+ return isHeader;
+}
+
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-printer.h Fri Jul 06 14:39:59 2007 -0700
@@ -0,0 +1,318 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_PRINTER_H
+#define PACKET_PRINTER_H
+
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "buffer.h"
+#include <vector>
+
+namespace {
+ class ItemList;
+}
+
+namespace ns3 {
+
+class Chunk;
+
+/**
+ * \brief hold a list of print callbacks for packet headers and trailers
+ *
+ * Users can register in instances of this class print callbacks
+ * which are used by Packet::Print to print the content of a packet.
+ */
+class PacketPrinter
+{
+public:
+ /**
+ * \brief indicates how many bytes were trimmed from a header
+ * or a trailer.
+ */
+ struct FragmentInformation
+ {
+ /**
+ * The number of bytes trimmed from the start of the header or the trailer.
+ */
+ uint32_t start;
+ /**
+ * The number of bytes trimmed from the end of the header or the trailer.
+ */
+ uint32_t end;
+ };
+ /**
+ * \brief callback to print payload.
+ *
+ * Arguments: output stream, packet uid, size, fragment information
+ */
+ typedef Callback<void,std::ostream &,uint32_t,uint32_t,struct PacketPrinter::FragmentInformation>
+ PayloadPrinter;
+
+ /**
+ * \brief callback to print fragmented chunks.
+ *
+ * Arguments: output stream, packet uid, size, header/trailer name, fragment information
+ */
+ typedef Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
+ ChunkFragmentPrinter;
+
+ /**
+ * \brief callback to print chunks for which no specific callback was specified.
+ *
+ * Arguments: output stream, packet uid, size, header/trailer name, fragment information
+ */
+ typedef Callback<void,std::ostream&,uint32_t,uint32_t,std::string&,struct PacketPrinter::FragmentInformation>
+ DefaultPrinter;
+
+ PacketPrinter ();
+
+ /**
+ * Print the content of the packet forward.
+ */
+ void PrintForward (void);
+ /**
+ * Print the content of the packet backward.
+ */
+ void PrintBackward (void);
+ void SetSeparator (std::string separator);
+ /**
+ * \param printer printer for payload
+ */
+ void AddPayloadPrinter (PayloadPrinter printer);
+ /**
+ * \param printer printer for the specified chunk
+ * \param fragmentPrinter printer for a fragment of the specified chunk
+ *
+ * If the user has not specified a callback for a specific header present
+ * in a packet, the "default" callback is invoked. If no such callback
+ * was specified, nothing happens.
+ */
+ template <typename T>
+ void AddHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ ChunkFragmentPrinter fragmentPrinter);
+ /**
+ * \param printer printer for the specified chunk
+ * \param fragmentPrinter printer for a fragment of the specified chunk
+ *
+ * If the user has not specified a callback for a specific trailer present
+ * in a packet, the "default" callback is invoked. If no such callback
+ * was specified, nothing happens.
+ */
+ template <typename T>
+ void AddTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ ChunkFragmentPrinter fragmentPrinter);
+ /**
+ * \param printer printer for a chunk for which no callback was specified explicitely
+ */
+ void AddDefaultPrinter (DefaultPrinter printer);
+
+private:
+ friend class PacketMetadata;
+ typedef void (*DoPrintCallback) (Ptr<CallbackImplBase>, Buffer::Iterator, std::ostream &,
+ uint32_t, uint32_t);
+ typedef std::string (*DoGetNameCallback) (void);
+ struct Printer
+ {
+ uint32_t m_chunkUid;
+ Ptr<CallbackImplBase> m_printer;
+ Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
+ m_fragmentPrinter;
+ };
+ struct RegisteredChunk
+ {
+ DoPrintCallback printCallback;
+ DoGetNameCallback getNameCallback;
+ bool isHeader;
+ };
+ typedef std::vector<struct PacketPrinter::Printer> PrinterList;
+ typedef std::vector<struct RegisteredChunk> RegisteredChunks;
+
+
+ static PacketPrinter GetDefault (void);
+ static PacketPrinter *PeekDefault (void);
+ static PacketPrinter *CreateStaticDefault (void);
+ static void DoDefaultPrintPayload (std::ostream & os,
+ uint32_t packetUid,
+ uint32_t size,
+ struct PacketPrinter::FragmentInformation info);
+ static void DoDefaultPrintDefault (std::ostream & os,
+ uint32_t packetUid,
+ uint32_t size,
+ std::string &name,
+ struct PacketPrinter::FragmentInformation info);
+ template <typename T>
+ static void DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk);
+ static void DoDefaultPrintFragment (std::ostream & os,
+ uint32_t packetUid,
+ uint32_t size,
+ std::string &name,
+ struct PacketPrinter::FragmentInformation info);
+
+ template <typename T>
+ static void DoPrint (Ptr<CallbackImplBase> callbackPrinter,
+ Buffer::Iterator i,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size);
+ template <typename T>
+ static std::string DoGetName (void);
+ template <typename T>
+ static uint32_t GetTrailerUid (void);
+ template <typename T>
+ static uint32_t GetHeaderUid (void);
+ template <typename T>
+ static uint32_t AllocateUid (bool isHeader);
+ static RegisteredChunks *GetRegisteredChunks (void);
+ static bool IsTrailer (uint32_t uid);
+ static bool IsHeader (uint32_t uid);
+
+
+ void PrintChunk (uint32_t uid,
+ Buffer::Iterator i,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size) const;
+ void PrintChunkFragment (uint32_t uid,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size,
+ uint32_t fragmentStart,
+ uint32_t fragmentEnd) const;
+ void PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
+ uint32_t fragmentStart, uint32_t fragmentEnd) const;
+ void DoAddPrinter (uint32_t uid,
+ Ptr<CallbackImplBase> printer,
+ Callback<void,
+ std::ostream &,
+ uint32_t,
+ uint32_t,
+ std::string &,
+ struct PacketPrinter::FragmentInformation> fragmentPrinter);
+
+ static PacketPrinter m_defaultPacketPrinter;
+ PrinterList m_printerList;
+ PayloadPrinter m_payloadPrinter;
+ DefaultPrinter m_defaultPrinter;
+ bool m_forward;
+ std::string m_separator;
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void
+PacketPrinter::AddHeaderPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
+ Callback<void,
+ std::ostream &,
+ uint32_t,
+ uint32_t,
+ std::string &,
+ struct PacketPrinter::FragmentInformation> fragmentPrinter)
+{
+ static uint32_t uid = PacketPrinter::GetHeaderUid<T> ();
+ DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
+}
+
+template <typename T>
+void
+PacketPrinter::AddTrailerPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
+ Callback<void,
+ std::ostream &,
+ uint32_t,
+ uint32_t,
+ std::string &,
+ struct PacketPrinter::FragmentInformation> fragmentPrinter)
+{
+ static uint32_t uid = PacketPrinter::GetTrailerUid<T> ();
+ DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
+}
+
+template <typename T>
+void
+PacketPrinter::DoPrint (Ptr<CallbackImplBase> printerCallback,
+ Buffer::Iterator i,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size)
+{
+ T chunk = T ();
+ chunk.Deserialize (i);
+ Callback<void,std::ostream&,uint32_t,uint32_t,const T*> callback;
+ callback.Assign (printerCallback);
+ callback (os, packetUid, size, &chunk);
+}
+
+template <typename T>
+std::string
+PacketPrinter::DoGetName (void)
+{
+ T chunk = T ();
+ return chunk.GetName ();
+}
+
+template <typename T>
+uint32_t
+PacketPrinter::GetHeaderUid (void)
+{
+ static uint32_t uid = PacketPrinter::AllocateUid<T> (true);
+ return uid;
+}
+
+template <typename T>
+uint32_t
+PacketPrinter::GetTrailerUid (void)
+{
+ static uint32_t uid = PacketPrinter::AllocateUid<T> (false);
+ return uid;
+}
+
+template <typename T>
+uint32_t
+PacketPrinter::AllocateUid (bool isHeader)
+{
+ RegisteredChunks *chunks = PacketPrinter::GetRegisteredChunks ();
+ RegisteredChunk chunk;
+ chunk.printCallback = &PacketPrinter::DoPrint<T>;
+ chunk.getNameCallback = &PacketPrinter::DoGetName<T>;
+ chunk.isHeader = isHeader;
+ chunks->push_back (chunk);
+ uint32_t uid = chunks->size () * 2;
+ PacketPrinter::PeekDefault ()->DoAddPrinter (uid,
+ MakeCallback (&PacketPrinter::DoDefaultPrint<T>).GetImpl (),
+ MakeCallback (&PacketPrinter::DoDefaultPrintFragment));
+ return uid;
+}
+
+template <typename T>
+void
+PacketPrinter::DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk)
+{
+ os << chunk->GetName () << " ";
+ chunk->Print (os);
+}
+
+
+
+} // namespace ns3
+
+#endif /* PACKET_PRINTER_H */
--- a/src/common/packet.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/packet.cc Fri Jul 06 14:39:59 2007 -0700
@@ -19,6 +19,7 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "packet.h"
+#include "packet-printer.h"
#include "ns3/assert.h"
namespace ns3 {
@@ -27,20 +28,20 @@
Packet::Packet ()
: m_buffer (),
- m_uid (m_globalUid)
+ m_metadata (m_globalUid, 0)
{
m_globalUid++;
}
Packet::Packet (uint32_t size)
: m_buffer (size),
- m_uid (m_globalUid)
+ m_metadata (m_globalUid, size)
{
m_globalUid++;
}
Packet::Packet (uint8_t const*buffer, uint32_t size)
: m_buffer (),
- m_uid (m_globalUid)
+ m_metadata (m_globalUid, size)
{
m_globalUid++;
m_buffer.AddAtStart (size);
@@ -48,17 +49,20 @@
i.Write (buffer, size);
}
-Packet::Packet (Buffer buffer, Tags tags, uint32_t uid)
+Packet::Packet (Buffer buffer, Tags tags, PacketMetadata metadata)
: m_buffer (buffer),
m_tags (tags),
- m_uid (uid)
+ m_metadata (metadata)
{}
Packet
Packet::CreateFragment (uint32_t start, uint32_t length) const
{
Buffer buffer = m_buffer.CreateFragment (start, length);
- return Packet (buffer, m_tags, m_uid);
+ NS_ASSERT (m_buffer.GetSize () >= start + length);
+ uint32_t end = m_buffer.GetSize () - (start + length);
+ PacketMetadata metadata = m_metadata.CreateFragment (start, end);
+ return Packet (buffer, m_tags, metadata);
}
uint32_t
@@ -70,6 +74,9 @@
void
Packet::AddAtEnd (Packet packet)
{
+ packet.m_buffer.TransformIntoRealBuffer ();
+ m_buffer.TransformIntoRealBuffer ();
+
Buffer src = packet.m_buffer;
m_buffer.AddAtEnd (src.GetSize ());
Buffer::Iterator destStart = m_buffer.End ();
@@ -79,21 +86,25 @@
* XXX: we might need to merge the tag list of the
* other packet into the current packet.
*/
+ m_metadata.AddAtEnd (packet.m_metadata);
}
void
Packet::AddPaddingAtEnd (uint32_t size)
{
m_buffer.AddAtEnd (size);
+ m_metadata.AddPaddingAtEnd (size);
}
void
Packet::RemoveAtEnd (uint32_t size)
{
m_buffer.RemoveAtEnd (size);
+ m_metadata.RemoveAtEnd (size);
}
void
Packet::RemoveAtStart (uint32_t size)
{
m_buffer.RemoveAtStart (size);
+ m_metadata.RemoveAtStart (size);
}
void
@@ -111,12 +122,26 @@
uint32_t
Packet::GetUid (void) const
{
- return m_uid;
+ return m_metadata.GetUid ();
}
void
Packet::Print (std::ostream &os) const
-{}
+{
+ m_metadata.PrintDefault (os, m_buffer);
+}
+
+void
+Packet::Print (std::ostream &os, const PacketPrinter &printer) const
+{
+ m_metadata.Print (os, m_buffer, printer);
+}
+
+void
+Packet::EnableMetadata (void)
+{
+ PacketMetadata::Enable ();
+}
}; // namespace ns3
--- a/src/common/packet.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/packet.h Fri Jul 06 14:39:59 2007 -0700
@@ -26,11 +26,14 @@
#include "header.h"
#include "trailer.h"
#include "tags.h"
+#include "packet-metadata.h"
#include "ns3/callback.h"
#include "ns3/assert.h"
namespace ns3 {
+class PacketPrinter;
+
/**
* \brief network packets
*
@@ -129,7 +132,7 @@
uint32_t GetSize (void) const;
/**
* Add header to this packet. This method invokes the
- * ns3::Header::GetSerializedSize and ns3::Header::SerializeTo
+ * ns3::Chunk::GetSerializedSize and ns3::Chunk::SerializeTo
* methods to reserve space in the buffer and request the
* header to serialize itself in the packet buffer.
*
@@ -139,8 +142,7 @@
void AddHeader (T const &header);
/**
* Deserialize and remove the header from the internal buffer.
- * This method invokes ns3::Header::DeserializeFrom
- * and then removes the deserialized bytes from the buffer.
+ * This method invokes ns3::Chunk::DeserializeFrom.
*
* \param header a reference to the header to remove from the internal buffer.
* \returns the number of bytes removed from the packet.
@@ -149,7 +151,7 @@
uint32_t RemoveHeader (T &header);
/**
* Add trailer to this packet. This method invokes the
- * ns3::Trailer::GetSerializedSize and ns3::Trailer::serializeTo
+ * ns3::Chunk::GetSerializedSize and ns3::Trailer::serializeTo
* methods to reserve space in the buffer and request the trailer
* to serialize itself in the packet buffer.
*
@@ -159,8 +161,7 @@
void AddTrailer (T const &trailer);
/**
* Remove a deserialized trailer from the internal buffer.
- * This method invokes the ns3::Trailer::DeserializeFrom method
- * and then removes the deserialized bytes from the buffer.
+ * This method invokes the ns3::Chunk::DeserializeFrom method.
*
* \param trailer a reference to the trailer to remove from the internal buffer.
* \returns the number of bytes removed from the end of the packet.
@@ -254,12 +255,50 @@
*/
uint32_t GetUid (void) const;
+ /**
+ * \param os output stream in which the data should be printed.
+ *
+ * Iterate over the headers and trailers present in this packet,
+ * from the first header to the last trailer and invoke, for
+ * each of them, the user-provided method Header::DoPrint or
+ * Trailer::DoPrint methods.
+ */
void Print (std::ostream &os) const;
+ /**
+ * \param os output stream in which the data should be printed.
+ * \param printer the output formatter to use to print
+ * the content of this packet.
+ *
+ * Iterate over the headers and trailers present in this packet,
+ * either in the "forward" (first header to last trailer) or in
+ * the "backward" (last trailer to first header) direction, as
+ * specified by the PacketPrinter::PrintForward or the
+ * PacketPrinter::PrintBackward methods. For each header, trailer,
+ * or fragment of a header or a trailer, invoke the user-specified
+ * print callback stored in the specified PacketPrinter.
+ */
+ void Print (std::ostream &os, const PacketPrinter &printer) const;
+
+ /**
+ * By default, packets do not keep around enough metadata to
+ * perform the operations requested by the Print methods. If you
+ * want to be able to invoke any of the two ::Print methods,
+ * you need to invoke this method at least once during the
+ * simulation setup and before any packet is created.
+ *
+ * The packet metadata is also used to perform extensive
+ * sanity checks at runtime when performing operations on a
+ * Packet. For example, this metadata is used to verify that
+ * when you remove a header from a packet, this same header
+ * was actually present at the front of the packet. These
+ * errors will be detected and will abort the program.
+ */
+ static void EnableMetadata (void);
private:
- Packet (Buffer buffer, Tags tags, uint32_t uid);
+ Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
Buffer m_buffer;
Tags m_tags;
- uint32_t m_uid;
+ PacketMetadata m_metadata;
static uint32_t m_globalUid;
};
@@ -282,6 +321,7 @@
uint32_t size = header.GetSize ();
m_buffer.AddAtStart (size);
header.Serialize (m_buffer.Begin ());
+ m_metadata.AddHeader (header, size);
}
template <typename T>
uint32_t
@@ -291,6 +331,7 @@
"Must pass Header subclass to Packet::RemoveHeader");
uint32_t deserialized = header.Deserialize (m_buffer.Begin ());
m_buffer.RemoveAtStart (deserialized);
+ m_metadata.RemoveHeader (header, deserialized);
return deserialized;
}
template <typename T>
@@ -303,6 +344,7 @@
m_buffer.AddAtEnd (size);
Buffer::Iterator end = m_buffer.End ();
trailer.Serialize (end);
+ m_metadata.AddTrailer (trailer, size);
}
template <typename T>
uint32_t
@@ -312,6 +354,7 @@
"Must pass Trailer subclass to Packet::RemoveTrailer");
uint32_t deserialized = trailer.Deserialize (m_buffer.End ());
m_buffer.RemoveAtEnd (deserialized);
+ m_metadata.RemoveTrailer (trailer, deserialized);
return deserialized;
}
--- a/src/common/trailer.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/trailer.h Fri Jul 06 14:39:59 2007 -0700
@@ -68,8 +68,25 @@
virtual ~Trailer ();
private:
/**
+ * \returns a user-readable name to identify this type of header.
+ *
+ * The string returned is expected to be a single word with
+ * all capital letters
+ */
+ virtual std::string DoGetName (void) const = 0;
+ /**
* \param os the std output stream in which this
* protocol trailer must print itself.
+ *
+ * Although the header is free to format its output as it
+ * wishes, it is recommended to follow a few rules to integrate
+ * with the packet pretty printer:
+ * - start with flags, small field values located between a
+ * pair of parens. Values should be separated by whitespace.
+ * - follow the parens with the important fields, separated by
+ * whitespace.
+ * i.e.:
+ * (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
*/
virtual void PrintTo (std::ostream &os) const = 0;
--- a/src/common/wscript Fri Jul 06 14:19:40 2007 -0700
+++ b/src/common/wscript Fri Jul 06 14:39:59 2007 -0700
@@ -10,9 +10,11 @@
common.uselib_local = ['ns3-core', 'ns3-simulator']
common.source = [
'buffer.cc',
+ 'chunk.cc',
'header.cc',
- 'chunk.cc',
'trailer.cc',
+ 'packet-printer.cc',
+ 'packet-metadata.cc',
'packet.cc',
'tags.cc',
'pcap-writer.cc',
@@ -28,11 +30,13 @@
headers = bld.create_obj('ns3header')
headers.source = [
'buffer.h',
+ 'chunk.h',
'header.h',
- 'chunk.h',
'trailer.h',
'tags.h',
'packet.h',
+ 'packet-printer.h',
+ 'packet-metadata.h',
'uv-trace-source.h',
'sv-trace-source.h',
'fv-trace-source.h',
--- a/src/core/callback.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/core/callback.h Fri Jul 06 14:39:59 2007 -0700
@@ -225,6 +225,7 @@
public:
virtual ~CallbackBase () {}
virtual CallbackImplBase *PeekImpl (void) const = 0;
+ virtual Ptr<CallbackImplBase> GetImpl (void) const = 0;
};
/**
@@ -278,7 +279,7 @@
: m_impl (impl)
{}
- bool IsNull (void) {
+ bool IsNull (void) const {
return (PeekImpl () == 0)?true:false;
}
void Nullify (void) {
@@ -330,6 +331,19 @@
const Callback<R, T1,T2,T3,T4,T5> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5> *> (&other);
*this = *goodType;
}
+ void Assign (Ptr<CallbackImplBase> other) {
+ CallbackImpl<R,T1,T2,T3,T4,T5> *impl = dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5> *> (PeekPointer (other));
+ if (other == 0)
+ {
+ NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")"
+ " got=" << typeid (other).name () <<
+ ", expected=" << typeid (*impl).name ());
+ }
+ *this = Callback<R,T1,T2,T3,T4,T5> (impl);
+ }
+ virtual Ptr<CallbackImplBase>GetImpl (void) const {
+ return m_impl;
+ }
private:
virtual CallbackImpl<R,T1,T2,T3,T4,T5> *PeekImpl (void) const {
return PeekPointer (m_impl);
--- a/src/internet-node/arp-header.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/internet-node/arp-header.cc Fri Jul 06 14:39:59 2007 -0700
@@ -83,24 +83,36 @@
return m_ipv4Dest;
}
+std::string
+ArpHeader::DoGetName (void) const
+{
+ return "ARP";
+}
void
ArpHeader::PrintTo (std::ostream &os) const
{
- os << "(arp)";
if (IsRequest ())
{
- os << " source mac: " << m_macSource
- << " source ipv4: " << m_ipv4Source
- << " dest ipv4: " << m_ipv4Dest;
+ os << "("
+ << "request "
+ << "source mac: " << m_macSource << " "
+ << "source ipv4: " << m_ipv4Source << " "
+ << "dest ipv4: " << m_ipv4Dest
+ << ")"
+ ;
}
else
{
NS_ASSERT (IsReply ());
- os << " source mac: " << m_macSource
- << " source ipv4: " << m_ipv4Source
- << " dest mac: " << m_macDest
- << " dest ipv4: " <<m_ipv4Dest;
+ os << "("
+ << "reply "
+ << "source mac: " << m_macSource << " "
+ << "source ipv4: " << m_ipv4Source << " "
+ << "dest mac: " << m_macDest << " "
+ << "dest ipv4: " <<m_ipv4Dest
+ << ")"
+ ;
}
}
uint32_t
--- a/src/internet-node/arp-header.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/internet-node/arp-header.h Fri Jul 06 14:39:59 2007 -0700
@@ -50,6 +50,7 @@
Ipv4Address GetDestinationIpv4Address (void);
private:
+ virtual std::string DoGetName (void) const;
/**
* \param os
*/
--- a/src/internet-node/ascii-trace.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/internet-node/ascii-trace.cc Fri Jul 06 14:39:59 2007 -0700
@@ -46,12 +46,14 @@
void
AsciiTrace::TraceAllQueues (void)
{
+ Packet::EnableMetadata ();
TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/*",
MakeCallback (&AsciiTrace::LogDevQueue, this));
}
void
AsciiTrace::TraceAllNetDeviceRx (void)
{
+ Packet::EnableMetadata ();
TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/rx",
MakeCallback (&AsciiTrace::LogDevRx, this));
}
@@ -115,7 +117,7 @@
context.Get (interfaceIndex);
m_os << "interface=" << interfaceIndex << " ";
m_os << "pkt-uid=" << packet.GetUid () << " ";
- PrintType (packet);
+ packet.Print (m_os);
m_os << std::endl;
}
void
@@ -129,7 +131,7 @@
context.Get (interfaceIndex);
m_os << "interface=" << interfaceIndex << " ";
m_os << "pkt-uid=" << p.GetUid () << " ";
- PrintType (p);
+ p.Print (m_os);
m_os << std::endl;
}
--- a/src/internet-node/ipv4-header.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/internet-node/ipv4-header.cc Fri Jul 06 14:39:59 2007 -0700
@@ -28,17 +28,6 @@
namespace ns3 {
-static uint16_t
-UtilsNtoh16 (uint16_t v)
-{
- uint16_t val;
- uint8_t *array;
- array = (uint8_t *)&v;
- val = (array[0] << 8) | (array[1] << 0);
- return val;
-}
-
-
bool Ipv4Header::m_calcChecksum = false;
Ipv4Header::Ipv4Header ()
@@ -190,21 +179,48 @@
return m_goodChecksum;
}
+std::string
+Ipv4Header::DoGetName (void) const
+{
+ return "IPV4";
+}
+
void
Ipv4Header::PrintTo (std::ostream &os) const
{
// ipv4, right ?
- os << "(ipv4)"
- << " tos=" << (uint32_t)m_tos
- << ", payload length=" << UtilsNtoh16 (m_payloadSize)
- << ", id=" << m_identification
- << ", " << (IsLastFragment ()?"last":"more")
- << ", " << (IsDontFragment ()?"dont":"may")
- << ", frag offset=" << m_fragmentOffset
- << ", ttl=" << m_ttl
- << ", protocol=" << m_protocol
- << ", source=" << m_source
- << ", destination=" << m_destination;
+ std::string flags;
+ if (m_flags == 0)
+ {
+ flags = "none";
+ }
+ else if (m_flags & MORE_FRAGMENTS &&
+ m_flags & DONT_FRAGMENT)
+ {
+ flags = "MF|DF";
+ }
+ else if (m_flags & DONT_FRAGMENT)
+ {
+ flags = "DF";
+ }
+ else if (m_flags & MORE_FRAGMENTS)
+ {
+ flags = "MF";
+ }
+ else
+ {
+ flags = "XX";
+ }
+ os << "("
+ << "tos 0x" << std::hex << m_tos << std::dec << " "
+ << "ttl " << m_ttl << " "
+ << "id " << m_identification << " "
+ << "offset " << m_fragmentOffset << " "
+ << "flags [" << flags << "] "
+ << "length: " << (m_payloadSize + 5 * 4)
+ << ") "
+ << m_source << " > " << m_destination
+ ;
}
uint32_t
Ipv4Header::GetSerializedSize (void) const
--- a/src/internet-node/ipv4-header.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/internet-node/ipv4-header.h Fri Jul 06 14:39:59 2007 -0700
@@ -140,6 +140,7 @@
bool IsChecksumOk (void) const;
private:
+ virtual std::string DoGetName (void) const;
virtual void PrintTo (std::ostream &os) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void SerializeTo (Buffer::Iterator start) const;
--- a/src/internet-node/udp-header.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/internet-node/udp-header.cc Fri Jul 06 14:39:59 2007 -0700
@@ -91,15 +91,20 @@
m_initialChecksum = Ipv4ChecksumCalculate (0, buf, 12);
}
-
+std::string
+UdpHeader::DoGetName (void) const
+{
+ return "UDP";
+}
void
UdpHeader::PrintTo (std::ostream &os) const
{
- os << "(udp)"
- << ", port source=" << m_sourcePort
- << ", port destination=" << m_destinationPort
- << ", length=" << m_payloadSize;
+ os << "("
+ << "length: " << m_payloadSize + GetSize ()
+ << ") "
+ << m_sourcePort << " > " << m_destinationPort
+ ;
}
uint32_t
--- a/src/internet-node/udp-header.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/internet-node/udp-header.h Fri Jul 06 14:39:59 2007 -0700
@@ -81,6 +81,7 @@
uint8_t protocol);
private:
+ virtual std::string DoGetName (void) const;
virtual void PrintTo (std::ostream &os) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void SerializeTo (Buffer::Iterator start) const;
--- a/src/node/llc-snap-header.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/node/llc-snap-header.cc Fri Jul 06 14:39:59 2007 -0700
@@ -47,14 +47,20 @@
return 1 + 1 + 1 + 3 + 2;
}
+std::string
+LlcSnapHeader::DoGetName (void) const
+{
+ return "LLCSNAP";
+}
+
void
LlcSnapHeader::PrintTo (std::ostream &os) const
{
- os << "(mac)"
- << " EtherType: ";
+ os << "(type 0x";
os.setf (std::ios::hex, std::ios::basefield);
os << m_etherType;
os.setf (std::ios::dec, std::ios::basefield);
+ os << ")";
}
void
--- a/src/node/llc-snap-header.h Fri Jul 06 14:19:40 2007 -0700
+++ b/src/node/llc-snap-header.h Fri Jul 06 14:39:59 2007 -0700
@@ -37,6 +37,7 @@
uint16_t GetType (void);
private:
+ virtual std::string DoGetName (void) const;
virtual void PrintTo (std::ostream &os) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void SerializeTo (Buffer::Iterator start) const;
--- a/src/simulator/time.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/src/simulator/time.cc Fri Jul 06 14:39:59 2007 -0700
@@ -191,7 +191,28 @@
std::ostream&
operator<< (std::ostream& os, Time const& time)
{
- os << time.GetTimeStep () << "ts";
+ std::string unit;
+ switch (TimeStepPrecision::Get ()) {
+ case TimeStepPrecision::S:
+ unit = "s";
+ break;
+ case TimeStepPrecision::MS:
+ unit = "ms";
+ break;
+ case TimeStepPrecision::US:
+ unit = "us";
+ break;
+ case TimeStepPrecision::NS:
+ unit = "ns";
+ break;
+ case TimeStepPrecision::PS:
+ unit = "ps";
+ break;
+ case TimeStepPrecision::FS:
+ unit = "fs";
+ break;
+ }
+ os << time.GetTimeStep () << unit;
return os;
}
--- a/src/simulator/wscript Fri Jul 06 14:19:40 2007 -0700
+++ b/src/simulator/wscript Fri Jul 06 14:39:59 2007 -0700
@@ -7,7 +7,9 @@
def set_options(opt):
opt.add_option('--high-precision-as-double',
help=('Whether to use a double floating point'
- ' type for high precision time values'),
+ ' type for high precision time values'
+ ' WARNING: this option only has effect '
+ 'with the configure command.'),
action="store_true", default=False,
dest='high_precision_as_double')
--- a/utils/bench-packets.cc Fri Jul 06 14:19:40 2007 -0700
+++ b/utils/bench-packets.cc Fri Jul 06 14:39:59 2007 -0700
@@ -18,97 +18,168 @@
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
-#include "ns3/wall-clock-ms.h"
+#include "ns3/system-wall-clock-ms.h"
#include "ns3/packet.h"
-#include "ns3/chunk-constant-data.h"
-#include "ns3/chunk-udp.h"
-#include "ns3/chunk-ipv4.h"
+#include "ns3/packet-metadata.h"
#include <iostream>
+#include <sstream>
using namespace ns3;
+template <int N>
+class BenchHeader : public Header
+{
+public:
+ BenchHeader ();
+ bool IsOk (void) const;
+private:
+ virtual std::string DoGetName (void) const;
+ virtual void PrintTo (std::ostream &os) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void SerializeTo (Buffer::Iterator start) const;
+ virtual uint32_t DeserializeFrom (Buffer::Iterator start);
+ bool m_ok;
+};
+
+template <int N>
+BenchHeader<N>::BenchHeader ()
+ : m_ok (false)
+{}
+
+template <int N>
+bool
+BenchHeader<N>::IsOk (void) const
+{
+ return m_ok;
+}
+
+template <int N>
+std::string
+BenchHeader<N>::DoGetName (void) const
+{
+ std::ostringstream oss;
+ oss << N;
+ return oss.str ();
+}
+
+template <int N>
+void
+BenchHeader<N>::PrintTo (std::ostream &os) const
+{
+ NS_ASSERT (false);
+}
+template <int N>
+uint32_t
+BenchHeader<N>::GetSerializedSize (void) const
+{
+ return N;
+}
+template <int N>
+void
+BenchHeader<N>::SerializeTo (Buffer::Iterator start) const
+{
+ start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+BenchHeader<N>::DeserializeFrom (Buffer::Iterator start)
+{
+ m_ok = true;
+ for (int i = 0; i < N; i++)
+ {
+ if (start.ReadU8 () != N)
+ {
+ m_ok = false;
+ }
+ }
+ return N;
+}
+
+
+
static void
benchPtrA (uint32_t n)
{
- ChunkConstantData data = ChunkConstantData (2000, 1);
- ChunkUdp udp;
- ChunkIpv4 ipv4;
+ BenchHeader<25> ipv4;
+ BenchHeader<8> udp;
for (uint32_t i = 0; i < n; i++) {
- Packet p;
- p.add (&data);
- p.add (&udp);
- p.add (&ipv4);
+ Packet p (2000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
Packet o = p;
- o.peek (&ipv4);
- o.remove (&ipv4);
- o.peek (&udp);
- o.remove (&udp);
- o.peek (&data);
- o.remove (&data);
+ o.RemoveHeader (ipv4);
+ o.RemoveHeader (udp);
}
}
static void
benchPtrB (uint32_t n)
{
- ChunkConstantData data = ChunkConstantData (2000, 1);
- ChunkUdp udp;
- ChunkIpv4 ipv4;
+ BenchHeader<25> ipv4;
+ BenchHeader<8> udp;
for (uint32_t i = 0; i < n; i++) {
- Packet p;
- p.add (&data);
- p.add (&udp);
- p.add (&ipv4);
+ Packet p (2000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
}
}
static void
ptrC2 (Packet p)
{
- ChunkConstantData data = ChunkConstantData (2000, 1);
- ChunkUdp udp;
+ BenchHeader<8> udp;
- p.peek (&udp);
- p.remove (&udp);
- p.peek (&data);
- p.remove (&data);
+ p.RemoveHeader (udp);
}
static void
ptrC1 (Packet p)
{
- ChunkIpv4 ipv4;
- p.peek (&ipv4);
- p.remove (&ipv4);
+ BenchHeader<25> ipv4;
+ p.RemoveHeader (ipv4);
ptrC2 (p);
}
static void
benchPtrC (uint32_t n)
{
- ChunkConstantData data = ChunkConstantData (2000, 1);
- ChunkUdp udp;
- ChunkIpv4 ipv4;
+ BenchHeader<25> ipv4;
+ BenchHeader<8> udp;
for (uint32_t i = 0; i < n; i++) {
- Packet p;
- p.add (&data);
- p.add (&udp);
- p.add (&ipv4);
+ Packet p (2000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
ptrC1 (p);
}
}
+static void
+benchPrint (uint32_t n)
+{
+ PacketPrinter printer;
+ BenchHeader<25> ipv4;
+ BenchHeader<8> udp;
+ Packet p (2000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
+
+ for (uint32_t i = 0; i < n; i++)
+ {
+ p.Print (std::cerr, printer);
+ }
+}
+
static void
runBench (void (*bench) (uint32_t), uint32_t n, char const *name)
{
- WallClockMs time;
- time.start ();
+ SystemWallClockMs time;
+ time.Start ();
(*bench) (n);
- unsigned long long deltaMs = time.end ();
+ unsigned long long deltaMs = time.End ();
double ps = n;
ps *= 1000;
ps /= deltaMs;
@@ -119,17 +190,31 @@
{
uint32_t n = 0;
while (argc > 0) {
- if (strncmp ("--n=", argv[0],strlen ("--n=")) == 0) {
+ if (strncmp ("--n=", argv[0],strlen ("--n=")) == 0)
+ {
char const *nAscii = argv[0] + strlen ("--n=");
n = atoi (nAscii);
- }
+ }
argc--;
argv++;
}
+
runBench (&benchPtrA, n, "a");
runBench (&benchPtrB, n, "b");
runBench (&benchPtrC, n, "c");
+ Packet::EnableMetadata ();
+ runBench (&benchPrint, n, "print");
+ PacketMetadata::SetOptOne (false);
+ runBench (&benchPtrA, n, "meta-a");
+ runBench (&benchPtrB, n, "meta-b");
+ runBench (&benchPtrC, n, "meta-c");
+ PacketMetadata::SetOptOne (true);
+ runBench (&benchPtrA, n, "meta-a-opt");
+ runBench (&benchPtrB, n, "meta-b-opt");
+ runBench (&benchPtrC, n, "meta-c-opt");
+
+
return 0;
}
--- a/wscript Fri Jul 06 14:19:40 2007 -0700
+++ b/wscript Fri Jul 06 14:39:59 2007 -0700
@@ -7,6 +7,7 @@
import Params
import Object
import pproc as subprocess
+import optparse
Params.g_autoconfig = 1
@@ -23,11 +24,32 @@
shutil.rmtree("doc/latex")
def set_options(opt):
+
+ def debug_option_callback(option, opt, value, parser):
+ if value == 'debug':
+ setattr(parser.values, option.dest, 'ultradebug')
+ elif value == 'optimized':
+ setattr(parser.values, option.dest, 'optimized')
+ else:
+ raise optparse.OptionValueError("allowed --debug-level values"
+ " are debug, optimized.")
+
+ opt.add_option('-d', '--debug-level',
+ action='callback',
+ type=str, dest='debug_level', default='debug',
+ help=('Specify the debug level, does nothing if CFLAGS is set'
+ ' in the environment. [Allowed Values: debug, optimized].'
+ ' WARNING: this option only has effect '
+ 'with the configure command.'),
+ callback=debug_option_callback)
+
# options provided by the modules
opt.tool_options('compiler_cxx')
opt.add_option('--enable-gcov',
- help=('Enable code coverage analysis'),
+ help=('Enable code coverage analysis.'
+ ' WARNING: this option only has effect '
+ 'with the configure command.'),
action="store_true", default=False,
dest='enable_gcov')
@@ -59,10 +81,13 @@
if not conf.check_tool('compiler_cxx'):
Params.fatal("No suitable compiler found")
-
# create the second environment, set the variant and set its name
variant_env = conf.env.copy()
- variant_name = Params.g_options.debug_level.lower()
+ debug_level = Params.g_options.debug_level.lower()
+ if debug_level == 'ultradebug':
+ variant_name = 'debug'
+ else:
+ variant_name = debug_level
if Params.g_options.enable_gcov:
variant_name += '-gcov'
@@ -79,13 +104,17 @@
conf.setenv(variant_name)
variant_env.append_value('CXXDEFINES', 'RUN_SELF_TESTS')
- variant_env.append_value('CXXFLAGS', ['-Wall', '-Werror'])
+
+ if os.path.basename(conf.env['CXX']).startswith("g++"):
+ variant_env.append_value('CXXFLAGS', ['-Wall', '-Werror'])
+
if 'debug' in Params.g_options.debug_level.lower():
variant_env.append_value('CXXDEFINES', 'NS3_DEBUG_ENABLE')
variant_env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE')
if sys.platform == 'win32':
- variant_env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc")
+ if os.path.basename(conf.env['CXX']).startswith("g++"):
+ variant_env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc")
conf.sub_config('src')
@@ -95,10 +124,7 @@
variant_env = bld.env_of_name(variant_name)
bld.m_allenvs['default'] = variant_env # switch to the active variant
- if Params.g_options.run:
- run_program(Params.g_options.run)
- return
- elif Params.g_options.shell:
+ if Params.g_options.shell:
run_shell()
return
@@ -125,11 +151,19 @@
if Params.g_options.doxygen:
doxygen()
+ if Params.g_options.run:
+ run_program(Params.g_options.run)
+
def _find_program(program_name):
+ found_programs = []
for obj in Object.g_allobjs:
+ if obj.m_type != 'program' or not obj.target:
+ continue
+ found_programs.append(obj.target)
if obj.target == program_name:
return obj
- raise ValueError("progam '%s' not found" % (program_name,))
+ raise ValueError("program '%s' not found; available programs are: %r"
+ % (program_name, found_programs))
def _run_argv(argv):
env = Params.g_build.env_of_name('default')
@@ -142,6 +176,9 @@
elif sys.platform == 'win32':
pathvar = 'PATH'
pathsep = ';'
+ elif sys.platform == 'cygwin':
+ pathvar = 'PATH'
+ pathsep = ':'
else:
Params.warning(("Don't know how to configure "
"dynamic library path for the platform '%s'") % (sys.platform,))
@@ -167,8 +204,8 @@
try:
program_obj = _find_program(program_name)
- except ValueError:
- Params.fatal("progam '%s' not found" % (program_name,))
+ except ValueError, ex:
+ Params.fatal(str(ex))
try:
program_node, = program_obj.m_linktask.m_outputs