diff --git a/examples/csma-packet-socket.cc b/examples/csma-packet-socket.cc index dfc267e0f..42dfb2e17 100644 --- a/examples/csma-packet-socket.cc +++ b/examples/csma-packet-socket.cc @@ -38,9 +38,6 @@ #include "ns3/node-module.h" #include "ns3/helper-module.h" -#include "ns3/ascii-trace.h" -#include "ns3/pcap-trace.h" - using namespace ns3; NS_LOG_COMPONENT_DEFINE ("CsmaPacketSocketExample"); @@ -105,9 +102,9 @@ main (int argc, char *argv[]) // Configure tracing of all enqueue, dequeue, and NetDevice receive events // Trace output will be sent to the csma-packet-socket.tr file NS_LOG_INFO ("Configure Tracing."); - AsciiTrace asciitrace ("csma-packet-socket.tr"); - asciitrace.TraceAllNetDeviceRx (); - asciitrace.TraceAllQueues (); + std::ofstream os; + os.open ("csma-packet-socket.tr"); + csma.EnableAsciiAll (os); NS_LOG_INFO ("Run Simulation."); Simulator::Run (); diff --git a/examples/mixed-global-routing.cc b/examples/mixed-global-routing.cc index f003571bf..f9f79e8dc 100644 --- a/examples/mixed-global-routing.cc +++ b/examples/mixed-global-routing.cc @@ -40,8 +40,6 @@ #include "ns3/simulator-module.h" #include "ns3/node-module.h" #include "ns3/helper-module.h" -#include "ns3/ascii-trace.h" -#include "ns3/pcap-trace.h" #include "ns3/global-route-manager.h" using namespace ns3; diff --git a/examples/mixed-wireless.cc b/examples/mixed-wireless.cc index 2e74f18c0..10e331b44 100644 --- a/examples/mixed-wireless.cc +++ b/examples/mixed-wireless.cc @@ -159,8 +159,12 @@ main (int argc, char *argv[]) MobilityHelper mobility; Ptr positionAlloc = CreateObject (); - positionAlloc->Add (Vector (0.0, 0.0, 0.0)); - positionAlloc->Add (Vector (5.0, 0.0, 0.0)); + double x = 0.0; + for (uint32_t i = 0; i < backboneNodes; ++i) + { + positionAlloc->Add (Vector (x, 0.0, 0.0)); + x += 5.0; + } mobility.SetPositionAllocator (positionAlloc); mobility.SetMobilityModel ("ns3::RandomDirection2dMobilityModel", "Bounds", RectangleValue (Rectangle (0, 1000, 0, 1000)), @@ -268,7 +272,6 @@ main (int argc, char *argv[]) { subnetAlloc->Add (Vector (0.0, j, 0.0)); } - mobility.EnableNotifier (); mobility.PushReferenceMobilityModel (backbone.Get (i)); mobility.SetPositionAllocator (subnetAlloc); mobility.SetMobilityModel ("ns3::RandomDirection2dMobilityModel", @@ -329,14 +332,13 @@ main (int argc, char *argv[]) // // Let's set up some ns-2-like ascii traces, using another helper class // - // Look at nodes 11, 13 only - // XXX todo - // asciiTrace.TraceQueues ("/NodeList/11|13/DeviceList/0"); - // asciiTrace.TraceNetDeviceRx ("/NodeList/11|13/DeviceList/0"); std::ofstream ascii; ascii.open ("mixed-wireless.tr"); WifiHelper::EnableAsciiAll (ascii); CsmaHelper::EnableAsciiAll (ascii); + // Look at nodes 11, 13 only + //WifiHelper::EnableAscii (ascii, 11, 0); + //WifiHelper::EnableAscii (ascii, 13, 0); // Let's do a pcap trace on the backbone devices WifiHelper::EnablePcap ("mixed-wireless", backboneDevices); @@ -344,10 +346,11 @@ main (int argc, char *argv[]) CsmaHelper::EnablePcap ("mixed-wireless", appSink->GetId (), 0); #ifdef ENABLE_FOR_TRACING_EXAMPLE - Config::Connect ("/NodeList/*/$MobilityModelNotifier/CourseChange", + Config::Connect ("/NodeList/*/$MobilityModel/CourseChange", MakeCallback (&CourseChangeCallback)); #endif + /////////////////////////////////////////////////////////////////////////// // // // Run simulation // diff --git a/samples/main-packet-tag.cc b/samples/main-packet-tag.cc index d5a8c6ec6..51ce8aea4 100644 --- a/samples/main-packet-tag.cc +++ b/samples/main-packet-tag.cc @@ -19,6 +19,7 @@ */ #include "ns3/tag.h" #include "ns3/packet.h" +#include "ns3/uinteger.h" #include using namespace ns3; @@ -27,22 +28,11 @@ using namespace ns3; class MyTag : public Tag { public: - // we have to define a public constructor - MyTag (); - // we have to define a public copy constructor - MyTag (const MyTag &other); - // we have to define a public destructor - ~MyTag (); - // we have to define a public static GetUid method - static uint32_t GetUid (void); - // we have to define a public Print method - void Print (std::ostream &os) const; - // we have to define a public GetSerializedSize method - uint32_t GetSerializedSize (void) const; - // we have to define a public Serialize method - void Serialize (Buffer::Iterator i) const; - // we have to define a public Deserialize method - uint32_t Deserialize (Buffer::Iterator i); + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); // these are our accessors to our tag structure void SetSimpleValue (uint8_t value); @@ -51,52 +41,40 @@ private: uint8_t m_simpleValue; }; -MyTag::MyTag () -{} -MyTag::MyTag (const MyTag &other) - : m_simpleValue (other.m_simpleValue) -{} -MyTag::~MyTag () -{} -uint32_t -MyTag::GetUid (void) +TypeId +MyTag::GetTypeId (void) { - // we input a unique string to AllocateUid - // to avoid name collisions. - static uint32_t uid = AllocateUid ("MyTag.tests.nsnam.org"); - return uid; + static TypeId tid = TypeId ("ns3::MyTag") + .SetParent () + .AddConstructor () + .AddAttribute ("SimpleValue", + "A simple value", + EmptyAttributeValue (), + MakeUintegerAccessor (&MyTag::GetSimpleValue), + MakeUintegerChecker ()) + ; + return tid; } -void -MyTag::Print (std::ostream &os) const +TypeId +MyTag::GetInstanceTypeId (void) const { - // print the content of this tag for Packet::PrintTags - os << "MyTag=0x" << std::hex << (uint32_t)m_simpleValue << std::dec; + return GetTypeId (); } uint32_t MyTag::GetSerializedSize (void) const { - // we do not want to deal with parallel simulations - // so we return 0. - return 0; + return 1; } void -MyTag::Serialize (Buffer::Iterator i) const +MyTag::Serialize (TagBuffer i) const { - // we will never be invoked because we are not doing - // parallel simulations so, we assert. - NS_ASSERT (false); + i.WriteU8 (m_simpleValue); } -uint32_t -MyTag::Deserialize (Buffer::Iterator i) +void +MyTag::Deserialize (TagBuffer i) { - // we will never be invoked because we are not doing - // parallel simulations so, we assert. - NS_ASSERT (false); - // theoretically, return the number of bytes read - return 0; + m_simpleValue = i.ReadU8 (); } - - void MyTag::SetSimpleValue (uint8_t value) { @@ -124,7 +102,7 @@ int main (int argc, char *argv[]) // read the tag from the packet copy MyTag tagCopy; - p->PeekTag (tagCopy); + p->FindFirstMatchingTag (tagCopy); // the copy and the original are the same ! NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ()); diff --git a/samples/main-random-topology.cc b/samples/main-random-topology.cc index ec34d1ec8..7e4f32334 100644 --- a/samples/main-random-topology.cc +++ b/samples/main-random-topology.cc @@ -25,7 +25,6 @@ int main (int argc, char *argv[]) c.Create (10000); MobilityHelper mobility; - mobility.EnableNotifier (); mobility.SetPositionAllocator ("ns3::RandomDiscPositionAllocator", "X", StringValue ("100.0"), "Y", StringValue ("100.0"), diff --git a/samples/main-random-walk.cc b/samples/main-random-walk.cc index 1ce1ae0ac..c0219a508 100644 --- a/samples/main-random-walk.cc +++ b/samples/main-random-walk.cc @@ -8,7 +8,7 @@ using namespace ns3; static void -CourseChange (ns3::TraceContext const&, Ptr mobility) +CourseChange (std::string foo, Ptr mobility) { Vector pos = mobility->GetPosition (); Vector vel = mobility->GetVelocity (); @@ -22,7 +22,7 @@ int main (int argc, char *argv[]) Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Mode", StringValue ("Time")); Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Time", StringValue ("2s")); Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Speed", StringValue ("Constant:1.0")); - Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Bounds", StringValue ("0:200:0:100")); + Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Bounds", StringValue ("0|200|0|200")); CommandLine cmd; cmd.Parse (argc, argv); @@ -31,7 +31,6 @@ int main (int argc, char *argv[]) c.Create (100); MobilityHelper mobility; - mobility.EnableNotifier (); mobility.SetPositionAllocator ("ns3::RandomDiscPositionAllocator", "X", StringValue ("100.0"), "Y", StringValue ("100.0"), @@ -40,9 +39,9 @@ int main (int argc, char *argv[]) "Mode", StringValue ("Time"), "Time", StringValue ("2s"), "Speed", StringValue ("Constant:1.0"), - "Bounds", StringValue ("0:200:0:100")); + "Bounds", StringValue ("0|200|0|200")); mobility.InstallAll (); - Config::Connect ("/NodeList/*/$ns3::MobilityModelNotifier/CourseChange", + Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange", MakeCallback (&CourseChange)); Simulator::StopAt (Seconds (100.0)); diff --git a/src/applications/udp-echo/udp-echo-client.cc b/src/applications/udp-echo/udp-echo-client.cc index 6276a5ec7..0d2713fca 100644 --- a/src/applications/udp-echo/udp-echo-client.cc +++ b/src/applications/udp-echo/udp-echo-client.cc @@ -93,7 +93,7 @@ UdpEchoClient::StartApplication (void) { NS_LOG_FUNCTION_NOARGS (); - if (!m_socket) + if (m_socket == 0) { TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); m_socket = Socket::CreateSocket (GetNode(), tid); @@ -111,7 +111,7 @@ UdpEchoClient::StopApplication () { NS_LOG_FUNCTION_NOARGS (); - if (!m_socket) + if (m_socket != 0) { m_socket->SetRecvCallback(MakeNullCallback > ()); } diff --git a/src/applications/udp-echo/udp-echo-server.cc b/src/applications/udp-echo/udp-echo-server.cc index 51b7904bd..135b2800a 100644 --- a/src/applications/udp-echo/udp-echo-server.cc +++ b/src/applications/udp-echo/udp-echo-server.cc @@ -69,7 +69,7 @@ UdpEchoServer::StartApplication (void) { NS_LOG_FUNCTION_NOARGS (); - if (!m_socket) + if (m_socket == 0) { TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); m_socket = Socket::CreateSocket (GetNode(), tid); @@ -85,7 +85,7 @@ UdpEchoServer::StopApplication () { NS_LOG_FUNCTION_NOARGS (); - if (!m_socket) + if (m_socket != 0) { m_socket->SetRecvCallback(MakeNullCallback > ()); } diff --git a/src/common/buffer.cc b/src/common/buffer.cc index 4c5efe725..5c5bc3bb5 100644 --- a/src/common/buffer.cc +++ b/src/common/buffer.cc @@ -333,9 +333,10 @@ Buffer::GetInternalEnd (void) const return m_end - (m_zeroAreaEnd - m_zeroAreaStart); } -void +bool Buffer::AddAtStart (uint32_t start) { + bool dirty; NS_ASSERT (CheckInternalState ()); bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart; if (m_start >= start && !isDirty) @@ -347,31 +348,11 @@ Buffer::AddAtStart (uint32_t start) */ NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart); m_start -= start; + dirty = m_start > m_data->m_dirtyStart; HEURISTICS (g_nAddNoRealloc++); } -#if 0 - // the following is an optimization - else if (m_start >= start) - { - struct BufferData *newData = Buffer::Create (m_data->m_size); - memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ()); - m_data->m_count--; - if (m_data->m_count == 0) - { - Buffer::Recycle (m_data); - } - m_data = newData; - - m_start -= start; - HEURISTICS (g_nAddRealloc++); - } else { - NS_ASSERT (m_start < start); -#else - else - { -#endif uint32_t newSize = GetInternalSize () + start; struct BufferData *newData = Buffer::Create (newSize); memcpy (newData->m_data + start, m_data->m_data + m_start, GetInternalSize ()); @@ -383,10 +364,13 @@ Buffer::AddAtStart (uint32_t start) m_data = newData; int32_t delta = start - m_start; - m_start = 0; + m_start += delta; m_zeroAreaStart += delta; m_zeroAreaEnd += delta; m_end += delta; + m_start -= start; + + dirty = true; HEURISTICS (g_nAddRealloc++); } @@ -396,10 +380,12 @@ Buffer::AddAtStart (uint32_t start) m_data->m_dirtyEnd = m_end; LOG_INTERNAL_STATE ("add start=" << start << ", "); NS_ASSERT (CheckInternalState ()); + return dirty; } -void +bool Buffer::AddAtEnd (uint32_t end) { + bool dirty; NS_ASSERT (CheckInternalState ()); bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd; if (GetInternalEnd () + end <= m_data->m_size && !isDirty) @@ -412,25 +398,10 @@ Buffer::AddAtEnd (uint32_t end) NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd); m_end += end; + dirty = m_end < m_data->m_dirtyEnd; + HEURISTICS (g_nAddNoRealloc++); } -#if 0 - // this is an optimization - else if (GetInternalEnd () + end > m_data->m_size) - { - struct BufferData *newData = Buffer::Create (newSize); - memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ()); - m_data->m_count--; - if (m_data->m_count == 0) - { - Buffer::Recycle (m_data); - } - m_data = newData; - - m_end += end; - HEURISTICS (g_nAddRealloc++); - } -#endif else { uint32_t newSize = GetInternalSize () + end; @@ -443,14 +414,15 @@ Buffer::AddAtEnd (uint32_t end) } m_data = newData; - - m_zeroAreaStart -= m_start; - m_zeroAreaEnd -= m_start; - m_end -= m_start; - m_start = 0; - + int32_t delta = -m_start; + m_zeroAreaStart += delta; + m_zeroAreaEnd += delta; + m_end += delta; + m_start += delta; m_end += end; + dirty = true; + HEURISTICS (g_nAddRealloc++); } HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart)); @@ -459,12 +431,16 @@ Buffer::AddAtEnd (uint32_t end) m_data->m_dirtyEnd = m_end; LOG_INTERNAL_STATE ("add end=" << end << ", "); NS_ASSERT (CheckInternalState ()); + + return dirty; } -void +void Buffer::AddAtEnd (const Buffer &o) { - if (m_end == m_zeroAreaEnd && + if (m_data->m_count == 1 && + m_end == m_zeroAreaEnd && + m_end == m_data->m_dirtyEnd && o.m_start == o.m_zeroAreaStart && o.m_zeroAreaEnd - o.m_zeroAreaStart > 0) { @@ -476,6 +452,7 @@ Buffer::AddAtEnd (const Buffer &o) uint32_t zeroSize = o.m_zeroAreaEnd - o.m_zeroAreaStart; m_zeroAreaEnd += zeroSize; m_end = m_zeroAreaEnd; + m_data->m_dirtyEnd = m_zeroAreaEnd; uint32_t endData = o.m_end - o.m_zeroAreaEnd; AddAtEnd (endData); Buffer::Iterator dst = End (); @@ -485,6 +462,7 @@ Buffer::AddAtEnd (const Buffer &o) dst.Write (src, o.End ()); return; } + Buffer dst = CreateFullCopy (); Buffer src = o.CreateFullCopy (); @@ -608,6 +586,18 @@ Buffer::CreateFullCopy (void) const return *this; } +int32_t +Buffer::GetCurrentStartOffset (void) const +{ + return m_start; +} +int32_t +Buffer::GetCurrentEndOffset (void) const +{ + return m_end; +} + + void Buffer::TransformIntoRealBuffer (void) const { diff --git a/src/common/buffer.h b/src/common/buffer.h index 3f8409aff..75f93f780 100644 --- a/src/common/buffer.h +++ b/src/common/buffer.h @@ -392,6 +392,7 @@ public: /** * \param start size to reserve + * \returns true if the buffer needed resizing, false otherwise. * * Add bytes at the start of the Buffer. The * content of these bytes is undefined but debugging @@ -399,9 +400,10 @@ public: * Any call to this method invalidates any Iterator * pointing to this Buffer. */ - void AddAtStart (uint32_t start); + bool AddAtStart (uint32_t start); /** * \param end size to reserve + * \returns true if the buffer needed resizing, false otherwise. * * Add bytes at the end of the Buffer. The * content of these bytes is undefined but debugging @@ -409,8 +411,15 @@ public: * Any call to this method invalidates any Iterator * pointing to this Buffer. */ - void AddAtEnd (uint32_t end); + bool AddAtEnd (uint32_t end); + /** + * \param o the buffer to append to the end of this buffer. + * + * Add bytes at the end of the Buffer. + * Any call to this method invalidates any Iterator + * pointing to this Buffer. + */ void AddAtEnd (const Buffer &o); /** * \param start size to remove @@ -451,6 +460,9 @@ public: Buffer CreateFullCopy (void) const; + int32_t GetCurrentStartOffset (void) const; + int32_t GetCurrentEndOffset (void) const; + Buffer (Buffer const &o); Buffer &operator = (Buffer const &o); Buffer (); diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index 1a75c6cdb..e8716e551 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -28,7 +28,9 @@ #include "packet.h" #include "packet-metadata.h" -namespace ns3 { +using namespace ns3; + +namespace { template class HistoryHeader : public Header @@ -191,6 +193,10 @@ HistoryTrailer::Deserialize (Buffer::Iterator start) return N; } +} + +namespace ns3 { + class PacketMetadataTest : public Test { @@ -607,6 +613,17 @@ PacketMetadataTest::RunTests (void) p = Create (16383); p = Create (16384); + + // bug 179. + p = Create (40); + p2 = p->CreateFragment (5, 5); + p3 = p->CreateFragment (10, 30); + ADD_HEADER (p2, 8); + ADD_HEADER (p3, 8); + REM_HEADER (p2, 8); + REM_HEADER (p3, 8); + p2->AddAtEnd (p3); + return ok; } diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index 0582577ef..3bc23f6ba 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -178,6 +178,14 @@ PacketMetadata::Append16 (uint16_t value, uint8_t *buffer) value >>= 8; buffer[1] = value; } +void +PacketMetadata::Append32 (uint32_t value, uint8_t *buffer) +{ + buffer[0] = value & 0xff; + buffer[1] = (value >> 8) & 0xff; + buffer[2] = (value >> 16) & 0xff; + buffer[3] = (value >> 24) & 0xff; +} bool PacketMetadata::TryToAppend16 (uint16_t value, uint8_t **pBuffer, uint8_t *end) { @@ -397,29 +405,24 @@ PacketMetadata::AddSmall (const struct PacketMetadata::SmallItem *item) NS_ASSERT (m_used != item->prev && m_used != item->next); 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 + uint32_t n = 2 + 2 + typeUidSize + sizeSize + 2; + if (m_used + n > m_data->m_size || + (m_head != 0xffff && + m_data->m_count != 1 && + m_used != m_data->m_dirtyEnd)) { ReserveCopy (n); - goto restart; } + 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); return n; } @@ -431,43 +434,40 @@ PacketMetadata::AddBig (uint32_t next, uint32_t prev, 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 typeUidSize = GetUleb128Size (typeUid); + uint32_t sizeSize = GetUleb128Size (item->size); + uint32_t fragStartSize = GetUleb128Size (extraItem->fragmentStart); + uint32_t fragEndSize = GetUleb128Size (extraItem->fragmentEnd); + uint32_t n = 2 + 2 + typeUidSize + sizeSize + 2 + fragStartSize + fragEndSize + 4; + + if (m_used + n > m_data->m_size || + (m_head != 0xffff && + m_data->m_count != 1 && + m_used != m_data->m_dirtyEnd)) + { + ReserveCopy (n); } - 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; + uint8_t *buffer = &m_data->m_data[m_used]; + + Append16 (next, buffer); + buffer += 2; + Append16 (prev, buffer); + buffer += 2; + AppendValue (typeUid, buffer); + buffer += typeUidSize; + AppendValue (item->size, buffer); + buffer += sizeSize; + Append16 (item->chunkUid, buffer); + buffer += 2; + AppendValue (extraItem->fragmentStart, buffer); + buffer += fragStartSize; + AppendValue (extraItem->fragmentEnd, buffer); + buffer += fragEndSize; + Append32 (extraItem->packetUid, buffer); + + return n; } void diff --git a/src/common/packet-metadata.h b/src/common/packet-metadata.h index 348970513..37285e960 100644 --- a/src/common/packet-metadata.h +++ b/src/common/packet-metadata.h @@ -249,13 +249,14 @@ private: uint32_t available); inline void UpdateHead (uint16_t written); inline void UpdateTail (uint16_t written); - uint32_t GetUleb128Size (uint32_t value) const; + inline 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 void Append32 (uint32_t value, uint8_t *buffer); inline bool TryToAppend (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); + inline 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); diff --git a/src/common/packet.cc b/src/common/packet.cc index 1e980c351..a79ac2a7e 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -24,6 +24,55 @@ namespace ns3 { uint32_t Packet::m_globalUid = 0; +TypeId +TagIterator::Item::GetTypeId (void) const +{ + return m_tid; +} +uint32_t +TagIterator::Item::GetStart (void) const +{ + return m_start; +} +uint32_t +TagIterator::Item::GetEnd (void) const +{ + return m_end; +} +void +TagIterator::Item::GetTag (Tag &tag) const +{ + if (tag.GetInstanceTypeId () != GetTypeId ()) + { + NS_FATAL_ERROR ("The tag you provided is not of the right type."); + } + tag.Deserialize (m_buffer); +} +TagIterator::Item::Item (TypeId tid, uint32_t start, uint32_t end, TagBuffer buffer) + : m_tid (tid), + m_start (start), + m_end (end), + m_buffer (buffer) +{} +bool +TagIterator::HasNext (void) const +{ + return m_current.HasNext (); +} +TagIterator::Item +TagIterator::Next (void) +{ + TagList::Iterator::Item i = m_current.Next (); + return TagIterator::Item (i.tid, + i.start-m_current.GetOffsetStart (), + i.end-m_current.GetOffsetStart (), + i.buf); +} +TagIterator::TagIterator (TagList::Iterator i) + : m_current (i) +{} + + void Packet::Ref (void) const { @@ -50,7 +99,7 @@ Packet::Copy (void) const Packet::Packet () : m_buffer (), - m_tags (), + m_tagList (), m_metadata (m_globalUid, 0), m_refCount (1) { @@ -59,7 +108,7 @@ Packet::Packet () Packet::Packet (const Packet &o) : m_buffer (o.m_buffer), - m_tags (o.m_tags), + m_tagList (o.m_tagList), m_metadata (o.m_metadata), m_refCount (1) {} @@ -72,14 +121,14 @@ Packet::operator = (const Packet &o) return *this; } m_buffer = o.m_buffer; - m_tags = o.m_tags; + m_tagList = o.m_tagList; m_metadata = o.m_metadata; return *this; } Packet::Packet (uint32_t size) : m_buffer (size), - m_tags (), + m_tagList (), m_metadata (m_globalUid, size), m_refCount (1) { @@ -87,7 +136,7 @@ Packet::Packet (uint32_t size) } Packet::Packet (uint8_t const*buffer, uint32_t size) : m_buffer (), - m_tags (), + m_tagList (), m_metadata (m_globalUid, size), m_refCount (1) { @@ -97,9 +146,9 @@ Packet::Packet (uint8_t const*buffer, uint32_t size) i.Write (buffer, size); } -Packet::Packet (Buffer buffer, Tags tags, PacketMetadata metadata) +Packet::Packet (const Buffer &buffer, const TagList &tagList, const PacketMetadata &metadata) : m_buffer (buffer), - m_tags (tags), + m_tagList (tagList), m_metadata (metadata), m_refCount (1) {} @@ -113,7 +162,7 @@ Packet::CreateFragment (uint32_t start, uint32_t length) const PacketMetadata metadata = m_metadata.CreateFragment (start, end); // again, call the constructor directly rather than // through Create because it is private. - return Ptr (new Packet (buffer, m_tags, metadata), false); + return Ptr (new Packet (buffer, m_tagList, metadata), false); } uint32_t @@ -126,7 +175,13 @@ void Packet::AddHeader (const Header &header) { uint32_t size = header.GetSerializedSize (); - m_buffer.AddAtStart (size); + uint32_t orgStart = m_buffer.GetCurrentStartOffset (); + bool resized = m_buffer.AddAtStart (size); + if (resized) + { + m_tagList.AddAtStart (m_buffer.GetCurrentStartOffset () - orgStart, + m_buffer.GetCurrentStartOffset () + size); + } header.Serialize (m_buffer.Begin ()); m_metadata.AddHeader (header, size); } @@ -142,7 +197,13 @@ void Packet::AddTrailer (const Trailer &trailer) { uint32_t size = trailer.GetSerializedSize (); - m_buffer.AddAtEnd (size); + uint32_t orgEnd = m_buffer.GetCurrentEndOffset (); + bool resized = m_buffer.AddAtEnd (size); + if (resized) + { + m_tagList.AddAtEnd (m_buffer.GetCurrentEndOffset () - orgEnd, + m_buffer.GetCurrentEndOffset () - size); + } Buffer::Iterator end = m_buffer.End (); trailer.Serialize (end); m_metadata.AddTrailer (trailer, size); @@ -159,17 +220,28 @@ Packet::RemoveTrailer (Trailer &trailer) void Packet::AddAtEnd (Ptr packet) { + uint32_t aStart = m_buffer.GetCurrentStartOffset (); + uint32_t bEnd = packet->m_buffer.GetCurrentEndOffset (); m_buffer.AddAtEnd (packet->m_buffer); - /** - * XXX: we might need to merge the tag list of the - * other packet into the current packet. - */ + uint32_t appendPrependOffset = m_buffer.GetCurrentEndOffset () - packet->m_buffer.GetSize (); + m_tagList.AddAtEnd (m_buffer.GetCurrentStartOffset () - aStart, + appendPrependOffset); + TagList copy = packet->m_tagList; + copy.AddAtStart (m_buffer.GetCurrentEndOffset () - bEnd, + appendPrependOffset); + m_tagList.Add (copy); m_metadata.AddAtEnd (packet->m_metadata); } void Packet::AddPaddingAtEnd (uint32_t size) { - m_buffer.AddAtEnd (size); + uint32_t orgEnd = m_buffer.GetCurrentEndOffset (); + bool resized = m_buffer.AddAtEnd (size); + if (resized) + { + m_tagList.AddAtEnd (m_buffer.GetCurrentEndOffset () - orgEnd, + m_buffer.GetCurrentEndOffset () - size); + } m_metadata.AddPaddingAtEnd (size); } void @@ -188,7 +260,7 @@ Packet::RemoveAtStart (uint32_t size) void Packet::RemoveAllTags (void) { - m_tags.RemoveAll (); + m_tagList.RemoveAll (); } uint8_t const * @@ -206,7 +278,8 @@ Packet::GetUid (void) const void Packet::PrintTags (std::ostream &os) const { - m_tags.Print (os, " "); + // XXX: + //m_tagList.Print (os, " "); } void @@ -350,20 +423,20 @@ Packet::Serialize (void) const m_metadata.Serialize (buffer.Begin (), reserve); // write tags - reserve = m_tags.GetSerializedSize (); - buffer.AddAtStart (reserve); - m_tags.Serialize (buffer.Begin (), reserve); + //XXX + //reserve = m_tags.GetSerializedSize (); + //buffer.AddAtStart (reserve); + //m_tags.Serialize (buffer.Begin (), reserve); // aggregate byte buffer, metadata, and tags Buffer tmp = m_buffer.CreateFullCopy (); - buffer.AddAtStart (tmp.GetSize ()); - buffer.Begin ().Write (tmp.Begin (), tmp.End ()); + tmp.AddAtEnd (buffer); // write byte buffer size. - buffer.AddAtStart (4); - buffer.Begin ().WriteU32 (m_buffer.GetSize ()); + tmp.AddAtStart (4); + tmp.Begin ().WriteU32 (m_buffer.GetSize ()); - return buffer; + return tmp; } void Packet::Deserialize (Buffer buffer) @@ -376,11 +449,13 @@ Packet::Deserialize (Buffer buffer) // read buffer. buf.RemoveAtEnd (buf.GetSize () - packetSize); m_buffer = buf; + buffer.RemoveAtStart (4 + packetSize); + // read tags - buffer.RemoveAtStart (4 + packetSize); - uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ()); - buffer.RemoveAtStart (tagsDeserialized); + //XXX + //uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ()); + //buffer.RemoveAtStart (tagsDeserialized); // read metadata uint32_t metadataDeserialized = @@ -388,6 +463,38 @@ Packet::Deserialize (Buffer buffer) buffer.RemoveAtStart (metadataDeserialized); } +void +Packet::AddTag (const Tag &tag) const +{ + TagList *list = const_cast (&m_tagList); + TagBuffer buffer = list->Add (tag.GetInstanceTypeId (), tag.GetSerializedSize (), + m_buffer.GetCurrentStartOffset (), + m_buffer.GetCurrentEndOffset ()); + tag.Serialize (buffer); +} +TagIterator +Packet::GetTagIterator (void) const +{ + return TagIterator (m_tagList.Begin (m_buffer.GetCurrentStartOffset (), m_buffer.GetCurrentEndOffset ())); +} + +bool +Packet::FindFirstMatchingTag (Tag &tag) const +{ + TypeId tid = tag.GetInstanceTypeId (); + TagIterator i = GetTagIterator (); + while (i.HasNext ()) + { + TagIterator::Item item = i.Next (); + if (tid == item.GetTypeId ()) + { + item.GetTag (tag); + return true; + } + } + return false; +} + std::ostream& operator<< (std::ostream& os, const Packet &packet) { packet.Print (os); @@ -403,24 +510,187 @@ std::ostream& operator<< (std::ostream& os, const Packet &packet) #include "ns3/test.h" #include +#include + +using namespace ns3; + +namespace { + +class ATestTagBase : public Tag +{ +public: + ATestTagBase () : m_error (false) {} + bool m_error; +}; + +template +class ATestTag : public ATestTagBase +{ +public: + static TypeId GetTypeId (void) { + std::ostringstream oss; + oss << "anon::ATestTag<" << N << ">"; + static TypeId tid = TypeId (oss.str ().c_str ()) + .SetParent () + .AddConstructor > () + .HideFromDocumentation () + ; + return tid; + } + virtual TypeId GetInstanceTypeId (void) const { + return GetTypeId (); + } + virtual uint32_t GetSerializedSize (void) const { + return N; + } + virtual void Serialize (TagBuffer buf) const { + for (uint32_t i = 0; i < N; ++i) + { + buf.WriteU8 (N); + } + } + virtual void Deserialize (TagBuffer buf) { + for (uint32_t i = 0; i < N; ++i) + { + uint8_t v = buf.ReadU8 (); + if (v != N) + { + m_error = true; + } + } + } + ATestTag () + : ATestTagBase () {} +}; + +class ATestHeaderBase : public Header +{ +public: + ATestHeaderBase () : Header (), m_error (false) {} + bool m_error; +}; + +template +class ATestHeader : public ATestHeaderBase +{ +public: + static TypeId GetTypeId (void) { + std::ostringstream oss; + oss << "anon::ATestHeader<" << N << ">"; + static TypeId tid = TypeId (oss.str ().c_str ()) + .SetParent
() + .AddConstructor > () + .HideFromDocumentation () + ; + return tid; + } + virtual TypeId GetInstanceTypeId (void) const { + return GetTypeId (); + } + virtual uint32_t GetSerializedSize (void) const { + return N; + } + virtual void Serialize (Buffer::Iterator iter) const { + for (uint32_t i = 0; i < N; ++i) + { + iter.WriteU8 (N); + } + } + virtual uint32_t Deserialize (Buffer::Iterator iter) { + for (uint32_t i = 0; i < N; ++i) + { + uint8_t v = iter.ReadU8 (); + if (v != N) + { + m_error = true; + } + } + return N; + } + virtual void Print (std::ostream &os) const { + } + ATestHeader () + : ATestHeaderBase () {} + +}; + +struct Expected +{ + Expected (uint32_t n_, uint32_t start_, uint32_t end_) + : n (n_), start (start_), end (end_) {} + + uint32_t n; + uint32_t start; + uint32_t end; +}; + +} + +#define E(a,b,c) a,b,c + +#define CHECK(p, n, ...) \ + if (!DoCheck (p, __FILE__, __LINE__, n, __VA_ARGS__)) \ + { \ + result = false; \ + } namespace ns3 { -class PacketTest: public Test { + +class PacketTest: public Test +{ public: - virtual bool RunTests (void); PacketTest (); + virtual bool RunTests (void); +private: + bool DoCheck (Ptr p, const char *file, int line, uint32_t n, ...); }; PacketTest::PacketTest () : Test ("Packet") {} +bool +PacketTest::DoCheck (Ptr p, const char *file, int line, uint32_t n, ...) +{ + bool result = true; + std::vector expected; + va_list ap; + va_start (ap, n); + for (uint32_t k = 0; k < n; ++k) + { + uint32_t N = va_arg (ap, uint32_t); + uint32_t start = va_arg (ap, uint32_t); + uint32_t end = va_arg (ap, uint32_t); + expected.push_back (Expected (N, start, end)); + } + va_end (ap); + + TagIterator i = p->GetTagIterator (); + uint32_t j = 0; + while (i.HasNext () && j < expected.size ()) + { + TagIterator::Item item = i.Next (); + struct Expected e = expected[j]; + std::ostringstream oss; + oss << "anon::ATestTag<" << e.n << ">"; + NS_TEST_ASSERT_EQUAL_FILELINE (item.GetTypeId ().GetName (), oss.str (), file, line); + NS_TEST_ASSERT_EQUAL_FILELINE (item.GetStart (), e.start, file, line); + NS_TEST_ASSERT_EQUAL_FILELINE (item.GetEnd (), e.end, file, line); + ATestTagBase *tag = dynamic_cast (item.GetTypeId ().GetConstructor () ()); + NS_TEST_ASSERT (tag != 0); + item.GetTag (*tag); + NS_TEST_ASSERT (!tag->m_error); + delete tag; + j++; + } + return result; +} bool PacketTest::RunTests (void) { - bool ok = true; + bool result = true; Ptr pkt1 = Create (reinterpret_cast ("hello"), 5); Ptr pkt2 = Create (reinterpret_cast (" world"), 6); @@ -428,25 +698,80 @@ PacketTest::RunTests (void) packet->AddAtEnd (pkt1); packet->AddAtEnd (pkt2); - if (packet->GetSize () != 11) - { - Failure () << "expected size 11, got " << packet->GetSize () << std::endl; - ok = false; - } + NS_TEST_ASSERT_EQUAL (packet->GetSize (), 11); std::string msg = std::string (reinterpret_cast(packet->PeekData ()), packet->GetSize ()); - if (msg != "hello world") - { - Failure () << "expected 'hello world', got '" << msg << "'" << std::endl; - ok = false; - } + NS_TEST_ASSERT_EQUAL (msg, "hello world"); - return ok; + + Ptr p = Create (1000); + + p->AddTag (ATestTag<1> ()); + CHECK (p, 1, E (1, 0, 1000)); + Ptr copy = p->Copy (); + CHECK (copy, 1, E (1, 0, 1000)); + + p->AddTag (ATestTag<2> ()); + CHECK (p, 2, E (1, 0, 1000), E(2, 0, 1000)); + CHECK (copy, 1, E (1, 0, 1000)); + + { + Packet c0 = *copy; + Packet c1 = *copy; + c0 = c1; + CHECK (&c0, 1, E (1, 0, 1000)); + CHECK (&c1, 1, E (1, 0, 1000)); + CHECK (copy, 1, E (1, 0, 1000)); + c0.AddTag (ATestTag<10> ()); + CHECK (&c0, 2, E (1, 0, 1000), E (10, 0, 1000)); + CHECK (&c1, 1, E (1, 0, 1000)); + CHECK (copy, 1, E (1, 0, 1000)); + } + + Ptr frag0 = p->CreateFragment (0, 10); + Ptr frag1 = p->CreateFragment (10, 90); + Ptr frag2 = p->CreateFragment (100, 900); + frag0->AddTag (ATestTag<3> ()); + CHECK (frag0, 3, E (1, 0, 10), E(2, 0, 10), E (3, 0, 10)); + frag1->AddTag (ATestTag<4> ()); + CHECK (frag1, 3, E (1, 0, 90), E(2, 0, 90), E (4, 0, 90)); + frag2->AddTag (ATestTag<5> ()); + CHECK (frag2, 3, E (1, 0, 900), E(2, 0, 900), E (5, 0, 900)); + + frag1->AddAtEnd (frag2); + CHECK (frag1, 6, E (1, 0, 90), E(2, 0, 90), E (4, 0, 90), E (1, 90, 990), E(2, 90, 990), E (5, 90, 990)); + + CHECK (frag0, 3, E (1, 0, 10), E(2, 0, 10), E (3, 0, 10)); + frag0->AddAtEnd (frag1); + CHECK (frag0, 9, + E (1, 0, 10), E(2, 0, 10), E (3, 0, 10), + E (1, 10, 100), E(2, 10, 100), E (4, 10, 100), + E (1, 100, 1000), E(2, 100, 1000), E (5, 100, 1000)); + + + // force caching a buffer of the right size. + frag0 = Create (1000); + frag0->AddHeader (ATestHeader<10> ()); + frag0 = 0; + + p = Create (1000); + p->AddTag (ATestTag<20> ()); + CHECK (p, 1, E (20, 0, 1000)); + frag0 = p->CreateFragment (10, 90); + CHECK (p, 1, E (20, 0, 1000)); + CHECK (frag0, 1, E (20, 0, 90)); + p = 0; + frag0->AddHeader (ATestHeader<10> ()); + CHECK (frag0, 1, E (20, 10, 100)); + + + + return result; } -static PacketTest gPacketTest; +static PacketTest g_packetTest; }; // namespace ns3 diff --git a/src/common/packet.h b/src/common/packet.h index 6d6d3f8d6..e79d82125 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -24,19 +24,81 @@ #include "buffer.h" #include "header.h" #include "trailer.h" -#include "tags.h" #include "packet-metadata.h" #include "tag.h" +#include "tag-list.h" #include "ns3/callback.h" #include "ns3/assert.h" #include "ns3/ptr.h" namespace ns3 { +/** + * \brief Iterator over the set of tags in a packet + * + * This is a java-style iterator. + */ +class TagIterator +{ +public: + /** + * Identifies a set tag and a set of bytes within a packet + * to which the tag applies. + */ + class Item + { + public: + /** + * \returns the ns3::TypeId associated to this tag. + */ + TypeId GetTypeId (void) const; + /** + * \returns the index of the first byte tagged by this tag. + * + * The index is an offset from the start of the packet. + */ + uint32_t GetStart (void) const; + /** + * \returns the index of the last byte tagged by this tag. + * + * The index is an offset from the start of the packet. + */ + uint32_t GetEnd (void) const; + /** + * \param tag the user tag to which the data should be copied. + * + * Read the requested tag and store it in the user-provided + * tag instance. This method will crash if the type of the + * tag provided by the user does not match the type of + * the underlying tag. + */ + void GetTag (Tag &tag) const; + private: + friend class TagIterator; + Item (TypeId tid, uint32_t start, uint32_t end, TagBuffer buffer); + TypeId m_tid; + uint32_t m_start; + uint32_t m_end; + TagBuffer m_buffer; + }; + /** + * \returns true if calling Next is safe, false otherwise. + */ + bool HasNext (void) const; + /** + * \returns the next item found and prepare for the next one. + */ + Item Next (void); +private: + friend class Packet; + TagIterator (TagList::Iterator i); + TagList::Iterator m_current; +}; + /** * \brief network packets * - * Each network packet contains a byte buffer, a list of tags, and + * Each network packet contains a byte buffer, a set of tags, and * metadata. * * - The byte buffer stores the serialized content of the headers and trailers @@ -45,13 +107,10 @@ namespace ns3 { * forces you to do this) which means that the content of a packet buffer * is expected to be that of a real packet. * - * - The list of tags stores an arbitrarily large set of arbitrary - * user-provided data structures in the packet: only one instance of - * each type of data structure is allowed in a list of tags. - * These tags typically contain per-packet cross-layer information or - * flow identifiers. Each tag stored in the tag list can be at most - * 16 bytes big. Trying to attach bigger data structures will trigger - * crashes at runtime. + * - Each tag tags a subset of the bytes in the packet byte buffer with the + * information stored in the tag. A classic example of a tag is a FlowIdTag + * which contains a flow id: the set of bytes tagged by this tag implicitely + * belong to the attached flow id. * * - The metadata describes the type of the headers and trailers which * were serialized in the byte buffer. The maintenance of metadata is @@ -83,6 +142,8 @@ public: * by getUid). */ Packet (); + Packet (const Packet &o); + Packet &operator = (const Packet &o); /** * Create a packet with a zero-filled payload. * The memory necessary for the payload is not allocated: @@ -151,63 +212,6 @@ public: * \returns the number of bytes removed from the end of the packet. */ uint32_t RemoveTrailer (Trailer &trailer); - /** - * \param tag a pointer to the tag to attach to this packet. - * - * Attach a tag to this packet. The tag is fully copied - * in a packet-specific internal buffer. This operation - * is expected to be really fast. The copy constructor of the - * tag is invoked to copy it into the tag buffer. - * - * Note that adding a tag is a const operation which is pretty - * un-intuitive. The rationale is that the content and behavior of - * a packet is _not_ changed when a tag is added to a packet: any - * code which was not aware of the new tag is going to work just - * the same if the new tag is added. The real reason why adding a - * tag was made a const operation is to allow a trace sink which gets - * a packet to tag the packet, even if the packet is const (and most - * trace sources should use const packets because it would be - * totally evil to allow a trace sink to modify the content of a - * packet). - * - */ - template - void AddTag (T const &tag) const; - /** - * Remove a tag from this packet. The data stored internally - * for this tag is copied in the input tag if an instance - * of this tag type is present in the internal buffer. If this - * tag type is not present, the input tag is not modified. - * - * This operation can be potentially slow and might trigger - * unexpectedly large memory allocations. It is thus - * usually a better idea to create a copy of this packet, - * and invoke removeAllTags on the copy to remove all - * tags rather than remove the tags one by one from a packet. - * - * \param tag a pointer to the tag to remove from this packet - * \returns true if an instance of this tag type is stored - * in this packet, false otherwise. - */ - template - bool RemoveTag (T &tag); - /** - * Copy a tag stored internally to the input tag. If no instance - * of this tag is present internally, the input tag is not modified. - * The copy constructor of the tag is invoked to copy it into the - * input tag variable. - * - * \param tag a pointer to the tag to read from this packet - * \returns true if an instance of this tag type is stored - * in this packet, false otherwise. - */ - template - bool PeekTag (T &tag) const; - /** - * Remove all the tags stored in this packet. This operation is - * much much faster than invoking removeTag n times. - */ - void RemoveAllTags (void); /** * \param os output stream in which the data should be printed. * @@ -330,12 +334,47 @@ public: * a different CPU. */ void Deserialize (Buffer buffer); + + /** + * \param tag the new tag to add to this packet + * + * Tag each byte included in this packet with the + * new tag. + * + * Note that adding a tag is a const operation which is pretty + * un-intuitive. The rationale is that the content and behavior of + * a packet is _not_ changed when a tag is added to a packet: any + * code which was not aware of the new tag is going to work just + * the same if the new tag is added. The real reason why adding a + * tag was made a const operation is to allow a trace sink which gets + * a packet to tag the packet, even if the packet is const (and most + * trace sources should use const packets because it would be + * totally evil to allow a trace sink to modify the content of a + * packet). + */ + void AddTag (const Tag &tag) const; + /** + * \returns an iterator over the set of tags included in this packet. + */ + TagIterator GetTagIterator (void) const; + /** + * \param tag the tag to search in this packet + * \returns true if the requested tag type was found, false otherwise. + * + * If the requested tag type is found, it is copied in the user's + * provided tag instance. + */ + bool FindFirstMatchingTag (Tag &tag) const; + + /** + * Remove all the tags stored in this packet. + */ + void RemoveAllTags (void); + private: - Packet (Buffer buffer, Tags tags, PacketMetadata metadata); - Packet (const Packet &o); - Packet &operator = (const Packet &o); + Packet (const Buffer &buffer, const TagList &tagList, const PacketMetadata &metadata); Buffer m_buffer; - Tags m_tags; + TagList m_tagList; PacketMetadata m_metadata; mutable uint32_t m_refCount; static uint32_t m_globalUid; @@ -381,42 +420,4 @@ std::ostream& operator<< (std::ostream& os, const Packet &packet); } // namespace ns3 - -/************************************************** - Start of implementation of templates defined - above - *************************************************/ - -namespace ns3 { - -template -void Packet::AddTag (T const& tag) const -{ - const Tag *parent; - // if the following assignment fails, it is because the - // input to this function is not a subclass of the Tag class. - parent = &tag; - m_tags.Add (tag); -} -template -bool Packet::RemoveTag (T & tag) -{ - Tag *parent; - // if the following assignment fails, it is because the - // input to this function is not a subclass of the Tag class. - parent = &tag; - return m_tags.Remove (tag); -} -template -bool Packet::PeekTag (T & tag) const -{ - Tag *parent; - // if the following assignment fails, it is because the - // input to this function is not a subclass of the Tag class. - parent = &tag; - return m_tags.Peek (tag); -} - -} // namespace ns3 - #endif /* PACKET_H */ diff --git a/src/common/pcap-writer.cc b/src/common/pcap-writer.cc index 121802215..a476b0734 100644 --- a/src/common/pcap-writer.cc +++ b/src/common/pcap-writer.cc @@ -46,7 +46,12 @@ PcapWriter::PcapWriter () PcapWriter::~PcapWriter () { + if (m_writer != 0) + { + m_writer->close (); + } delete m_writer; + m_writer = 0; } void diff --git a/src/common/tag-buffer.cc b/src/common/tag-buffer.cc new file mode 100644 index 000000000..9d9011b31 --- /dev/null +++ b/src/common/tag-buffer.cc @@ -0,0 +1,193 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * 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 + */ +#include "tag-buffer.h" +#include "ns3/assert.h" +#include + +namespace ns3 { + +#ifndef TAG_BUFFER_USE_INLINE + +void +TagBuffer::WriteU8 (uint8_t v) +{ + NS_ASSERT (m_current + 1 <= m_end); + *m_current = v; + m_current++; +} + +void +TagBuffer::WriteU16 (uint16_t data) +{ + WriteU8 ((data >> 0) & 0xff); + WriteU8 ((data >> 8) & 0xff); +} +void +TagBuffer::WriteU32 (uint32_t data) +{ + WriteU8 ((data >> 0) & 0xff); + WriteU8 ((data >> 8) & 0xff); + WriteU8 ((data >> 16) & 0xff); + WriteU8 ((data >> 24) & 0xff); +} + + +uint8_t +TagBuffer::ReadU8 (void) +{ + NS_ASSERT (m_current + 1 <= m_end); + uint8_t v; + v = *m_current; + m_current++; + return v; +} + +uint16_t +TagBuffer::ReadU16 (void) +{ + uint8_t byte0 = ReadU8 (); + uint8_t byte1 = ReadU8 (); + uint16_t data = byte1; + data <<= 8; + data |= byte0; + return data; +} +uint32_t +TagBuffer::ReadU32 (void) +{ + uint8_t byte0 = ReadU8 (); + uint8_t byte1 = ReadU8 (); + uint8_t byte2 = ReadU8 (); + uint8_t byte3 = ReadU8 (); + uint32_t data = byte3; + data <<= 8; + data |= byte2; + data <<= 8; + data |= byte1; + data <<= 8; + data |= byte0; + return data; +} + +#endif /* TAG_BUFFER_USE_INLINE */ + + +void +TagBuffer::WriteU64 (uint64_t data) +{ + WriteU8 ((data >> 0) & 0xff); + WriteU8 ((data >> 8) & 0xff); + WriteU8 ((data >> 16) & 0xff); + WriteU8 ((data >> 24) & 0xff); + WriteU8 ((data >> 32) & 0xff); + WriteU8 ((data >> 40) & 0xff); + WriteU8 ((data >> 48) & 0xff); + WriteU8 ((data >> 54) & 0xff); +} +void +TagBuffer::WriteDouble (double v) +{ + uint8_t *buf = (uint8_t *)&v; + for (uint32_t i = 0; i < sizeof (double); ++i, ++buf) + { + WriteU8 (*buf); + } +} +void +TagBuffer::Write (const uint8_t *buffer, uint32_t size) +{ + for (uint32_t i = 0; i < size; ++i, ++buffer) + { + WriteU8 (*buffer); + } +} +uint64_t +TagBuffer::ReadU64 (void) +{ + uint8_t byte0 = ReadU8 (); + uint8_t byte1 = ReadU8 (); + uint8_t byte2 = ReadU8 (); + uint8_t byte3 = ReadU8 (); + uint8_t byte4 = ReadU8 (); + uint8_t byte5 = ReadU8 (); + uint8_t byte6 = ReadU8 (); + uint8_t byte7 = ReadU8 (); + uint32_t data = byte7; + data <<= 8; + data |= byte6; + data <<= 8; + data |= byte5; + data <<= 8; + data |= byte4; + data <<= 8; + data |= byte3; + data <<= 8; + data |= byte2; + data <<= 8; + data |= byte1; + data <<= 8; + data |= byte0; + + return data; +} +double +TagBuffer::ReadDouble (void) +{ + double v; + uint8_t *buf = (uint8_t *)&v; + for (uint32_t i = 0; i < sizeof (double); ++i, ++buf) + { + *buf = ReadU8 (); + } + return v; +} +void +TagBuffer::Read (uint8_t *buffer, uint32_t size) +{ + for (uint32_t i = 0; i < size; ++i, ++buffer) + { + *buffer = ReadU8 (); + } +} +TagBuffer::TagBuffer (uint8_t *start, uint8_t *end) + : m_current (start), + m_end (end) +{} + +void +TagBuffer::TrimAtEnd (uint32_t trim) +{ + NS_ASSERT (m_current <= (m_end - trim)); + m_end -= trim; +} + +void +TagBuffer::CopyFrom (TagBuffer o) +{ + NS_ASSERT (o.m_end >= o.m_current); + NS_ASSERT (m_end >= m_current); + uintptr_t size = o.m_end - o.m_current; + NS_ASSERT (size <= (uintptr_t)(m_end - m_current)); + memcpy (m_current, o.m_current, size); + m_current += size; +} + +} // namespace ns3 + diff --git a/src/common/tag-buffer.h b/src/common/tag-buffer.h new file mode 100644 index 000000000..2e5836a21 --- /dev/null +++ b/src/common/tag-buffer.h @@ -0,0 +1,139 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * 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 + */ +#ifndef TAG_BUFFER_H +#define TAG_BUFFER_H + +#include + +#define TAG_BUFFER_USE_INLINE 1 + +#ifdef TAG_BUFFER_USE_INLINE +#define TAG_BUFFER_INLINE inline +#else +#define TAG_BUFFER_INLINE +#endif + +namespace ns3 { + +/** + * \brief read and write tag data + * + * This class allows subclasses of the ns3::Tag base class + * to serialize and deserialize their data. + */ +class TagBuffer +{ +public: + TagBuffer (uint8_t *start, uint8_t *end); + void TrimAtEnd (uint32_t trim); + + TAG_BUFFER_INLINE void WriteU8 (uint8_t v); + TAG_BUFFER_INLINE void WriteU16 (uint16_t v); + TAG_BUFFER_INLINE void WriteU32 (uint32_t v); + void WriteU64 (uint64_t v); + void WriteDouble (double v); + void Write (const uint8_t *buffer, uint32_t size); + TAG_BUFFER_INLINE uint8_t ReadU8 (void); + TAG_BUFFER_INLINE uint16_t ReadU16 (void); + TAG_BUFFER_INLINE uint32_t ReadU32 (void); + uint64_t ReadU64 (void); + double ReadDouble (void); + void Read (uint8_t *buffer, uint32_t size); + + void CopyFrom (TagBuffer o); +private: + + uint8_t *m_current; + uint8_t *m_end; +}; + +} // namespace ns3 + +#ifdef TAG_BUFFER_USE_INLINE + +#include "ns3/assert.h" + +namespace ns3 { + +void +TagBuffer::WriteU8 (uint8_t v) +{ + NS_ASSERT (m_current + 1 <= m_end); + *m_current = v; + m_current++; +} + +void +TagBuffer::WriteU16 (uint16_t data) +{ + WriteU8 ((data >> 0) & 0xff); + WriteU8 ((data >> 8) & 0xff); +} +void +TagBuffer::WriteU32 (uint32_t data) +{ + WriteU8 ((data >> 0) & 0xff); + WriteU8 ((data >> 8) & 0xff); + WriteU8 ((data >> 16) & 0xff); + WriteU8 ((data >> 24) & 0xff); +} + +uint8_t +TagBuffer::ReadU8 (void) +{ + NS_ASSERT (m_current + 1 <= m_end); + uint8_t v; + v = *m_current; + m_current++; + return v; +} + +uint16_t +TagBuffer::ReadU16 (void) +{ + uint8_t byte0 = ReadU8 (); + uint8_t byte1 = ReadU8 (); + uint16_t data = byte1; + data <<= 8; + data |= byte0; + return data; +} +uint32_t +TagBuffer::ReadU32 (void) +{ + uint8_t byte0 = ReadU8 (); + uint8_t byte1 = ReadU8 (); + uint8_t byte2 = ReadU8 (); + uint8_t byte3 = ReadU8 (); + uint32_t data = byte3; + data <<= 8; + data |= byte2; + data <<= 8; + data |= byte1; + data <<= 8; + data |= byte0; + return data; +} + +} // namespace ns3 + +#endif /* TAG_BUFFER_USE_INLINE */ + +#endif /* TAG_BUFFER_H */ diff --git a/src/common/tag-list.cc b/src/common/tag-list.cc new file mode 100644 index 000000000..3165d6b0e --- /dev/null +++ b/src/common/tag-list.cc @@ -0,0 +1,402 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * 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 + */ +#include "tag-list.h" +#include + +#define USE_FREE_LIST 1 +#define FREE_LIST_SIZE 1000 + +namespace ns3 { + +struct TagListData { + uint32_t size; + uint32_t count; + uint32_t dirty; + uint8_t data[4]; +}; + +#ifdef USE_FREE_LIST +static class TagListDataFreeList : public std::vector +{ +public: + ~TagListDataFreeList (); +} g_freeList; +static uint32_t g_maxSize = 0; + +TagListDataFreeList::~TagListDataFreeList () +{ + for (TagListDataFreeList::iterator i = begin (); + i != end (); i++) + { + uint8_t *buffer = (uint8_t *)(*i); + delete [] buffer; + } +} +#endif /* USE_FREE_LIST */ + +TagList::Iterator::Item::Item (TagBuffer buf_) + : buf (buf_) +{} + +bool +TagList::Iterator::HasNext (void) const +{ + return m_current < m_end; +} +struct TagList::Iterator::Item +TagList::Iterator::Next (void) +{ + NS_ASSERT (HasNext ()); + struct Item item = Item (TagBuffer (m_current+16, m_end)); + item.tid.SetUid (m_nextTid); + item.size = m_nextSize; + item.start = m_nextStart; + item.end = m_nextEnd; + item.start = std::max (item.start, m_offsetStart); + item.end = std::min (item.end, m_offsetEnd); + m_current += 4 + 4 + 4 + 4 + item.size; + item.buf.TrimAtEnd (m_end - m_current); + PrepareForNext (); + return item; +} +void +TagList::Iterator::PrepareForNext (void) +{ + while (m_current < m_end) + { + TagBuffer buf = TagBuffer (m_current, m_end); + m_nextTid = buf.ReadU32 (); + m_nextSize = buf.ReadU32 (); + m_nextStart = buf.ReadU32 (); + m_nextEnd = buf.ReadU32 (); + if (m_nextStart > m_offsetEnd || m_nextEnd < m_offsetStart) + { + m_current += 4 + 4 + 4 + 4 + m_nextSize; + } + else + { + break; + } + } +} +TagList::Iterator::Iterator (uint8_t *start, uint8_t *end, uint32_t offsetStart, uint32_t offsetEnd) + : m_current (start), + m_end (end), + m_offsetStart (offsetStart), + m_offsetEnd (offsetEnd) +{ + PrepareForNext (); +} + +uint32_t +TagList::Iterator::GetOffsetStart (void) const +{ + return m_offsetStart; +} + + +TagList::TagList () + : m_used (0), + m_data (0) +{} +TagList::TagList (const TagList &o) + : m_used (o.m_used), + m_data (o.m_data) +{ + if (m_data != 0) + { + m_data->count++; + } +} +TagList & +TagList::operator = (const TagList &o) +{ + if (this == &o) + { + return *this; + } + + Deallocate (m_data); + m_data = o.m_data; + m_used = o.m_used; + if (m_data != 0) + { + m_data->count++; + } + return *this; +} +TagList::~TagList () +{ + Deallocate (m_data); + m_data = 0; + m_used = 0; +} + +TagBuffer +TagList::Add (TypeId tid, uint32_t bufferSize, uint32_t start, uint32_t end) +{ + uint32_t spaceNeeded = m_used + bufferSize + 4 + 4 + 4 + 4; + NS_ASSERT (m_used <= spaceNeeded); + if (m_data == 0) + { + m_data = Allocate (spaceNeeded); + m_used = 0; + } + else if (m_data->size < spaceNeeded || + (m_data->count != 1 && m_data->dirty != m_used)) + { + struct TagListData *newData = Allocate (spaceNeeded); + memcpy (&newData->data, &m_data->data, m_used); + Deallocate (m_data); + m_data = newData; + } + TagBuffer tag = TagBuffer (&m_data->data[m_used], + &m_data->data[spaceNeeded]); + tag.WriteU32 (tid.GetUid ()); + tag.WriteU32 (bufferSize); + tag.WriteU32 (start); + tag.WriteU32 (end); + m_used = spaceNeeded; + m_data->dirty = m_used; + return tag; +} + +void +TagList::Add (const TagList &o) +{ + TagList::Iterator i = o.Begin (0, 0xffffffff); + while (i.HasNext ()) + { + TagList::Iterator::Item item = i.Next (); + TagBuffer buf = Add (item.tid, item.size, item.start, item.end); + buf.CopyFrom (item.buf); + } +} + +void +TagList::Remove (const Iterator &i) +{ + if (m_data == 0) + { + return; + } + // XXX +} + +void +TagList::RemoveAll (void) +{ + Deallocate (m_data); + m_data = 0; + m_used = 0; +} + +TagList::Iterator +TagList::Begin (uint32_t offsetStart, uint32_t offsetEnd) const +{ + if (m_data == 0) + { + return Iterator (0, 0, offsetStart, offsetEnd); + } + else + { + return Iterator (m_data->data, &m_data->data[m_used], offsetStart, offsetEnd); + } +} + +bool +TagList::IsDirtyAtEnd (uint32_t appendOffset) +{ + TagList::Iterator i = Begin (0, 0xffffffff); + while (i.HasNext ()) + { + TagList::Iterator::Item item = i.Next (); + if (item.end > appendOffset) + { + return true; + } + } + return false; +} + +bool +TagList::IsDirtyAtStart (uint32_t prependOffset) +{ + TagList::Iterator i = Begin (0, 0xffffffff); + while (i.HasNext ()) + { + TagList::Iterator::Item item = i.Next (); + if (item.start < prependOffset) + { + return true; + } + } + return false; +} + +void +TagList::AddAtEnd (int32_t adjustment, uint32_t appendOffset) +{ + if (adjustment == 0 && !IsDirtyAtEnd (appendOffset)) + { + return; + } + TagList list; + TagList::Iterator i = Begin (0, 0xffffffff); + while (i.HasNext ()) + { + TagList::Iterator::Item item = i.Next (); + item.start += adjustment; + item.end += adjustment; + + if (item.start > appendOffset) + { + continue; + } + else if (item.start < appendOffset && item.end > appendOffset) + { + item.end = appendOffset; + } + else + { + // nothing to do. + } + TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end); + buf.CopyFrom (item.buf); + } + *this = list; +} + +void +TagList::AddAtStart (int32_t adjustment, uint32_t prependOffset) +{ + if (adjustment == 0 && !IsDirtyAtStart (prependOffset)) + { + return; + } + TagList list; + TagList::Iterator i = Begin (0, 0xffffffff); + while (i.HasNext ()) + { + TagList::Iterator::Item item = i.Next (); + item.start += adjustment; + item.end += adjustment; + + if (item.end < prependOffset) + { + continue; + } + else if (item.end > prependOffset && item.start < prependOffset) + { + item.start = prependOffset; + } + else + { + // nothing to do. + } + TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end); + buf.CopyFrom (item.buf); + } + *this = list; +} + +#ifdef USE_FREE_LIST + +struct TagListData * +TagList::Allocate (uint32_t size) +{ + while (!g_freeList.empty ()) + { + struct TagListData *data = g_freeList.back (); + g_freeList.pop_back (); + NS_ASSERT (data != 0); + if (data->size >= size) + { + data->count = 1; + data->dirty = 0; + return data; + } + uint8_t *buffer = (uint8_t *)data; + delete [] buffer; + } + uint8_t *buffer = new uint8_t [std::max (size, g_maxSize) + sizeof (struct TagListData) - 4]; + struct TagListData *data = (struct TagListData *)buffer; + data->count = 1; + data->size = size; + data->dirty = 0; + return data; +} + +void +TagList::Deallocate (struct TagListData *data) +{ + if (data == 0) + { + return; + } + g_maxSize = std::max (g_maxSize, data->size); + data->count--; + if (data->count == 0) + { + if (g_freeList.size () > FREE_LIST_SIZE || + data->size < g_maxSize) + { + uint8_t *buffer = (uint8_t *)data; + delete [] buffer; + } + else + { + g_freeList.push_back (data); + } + } +} + +#else /* USE_FREE_LIST */ + +struct TagListData * +TagList::Allocate (uint32_t size) +{ + uint8_t *buffer = new uint8_t [size + sizeof (struct TagListData) - 4]; + struct TagListData *data = (struct TagListData *)buffer; + data->count = 1; + data->size = size; + data->dirty = 0; + return data; +} + +void +TagList::Deallocate (struct TagListData *data) +{ + if (data == 0) + { + return; + } + data->count--; + if (data->count == 0) + { + uint8_t *buffer = (uint8_t *)data; + delete [] buffer; + } +} + +#endif /* USE_FREE_LIST */ + + +} // namespace ns3 diff --git a/src/common/tag-list.h b/src/common/tag-list.h new file mode 100644 index 000000000..10cf3ff60 --- /dev/null +++ b/src/common/tag-list.h @@ -0,0 +1,173 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * 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 + */ +#ifndef TAG_LIST_H +#define TAG_LIST_H + +#include +#include "ns3/type-id.h" +#include "tag-buffer.h" + +namespace ns3 { + +struct TagListData; + +/** + * \brief keep track of the tags stored in a packet. + * + * This class is mostly private to the Packet implementation and users + * should never have to access it directly. + * + * \internal + * The implementation of this class is a bit tricky so, there are a couple + * of things to keep in mind here: + * + * - it stores all tags in a single byte buffer: each tag is stored + * as 4 32bit integers (TypeId, tag data size, start, end) followed + * by the tag data as generated by Tag::Serialize. + * + * - the struct TagListData structure which contains the tag byte buffer + * is shared and, thus, reference-counted. This data structure is unshared + * as-needed to emulate COW semantics. + * + * - each tag tags a unique set of bytes identified by the pair of offsets + * (start,end). These offsets are provided by Buffer::GetCurrentStartOffset + * and Buffer::GetCurrentEndOffset which means that they are relative to + * the start of the 'virtual byte buffer' as explained in the documentation + * for the ns3::Buffer class. Whenever the origin of the offset of the Buffer + * instance associated to this TagList instance changes, the Buffer class + * reports this to its container Packet class as a bool return value + * in Buffer::AddAtStart and Buffer::AddAtEnd. In both cases, when this happens + * the Packet class calls TagList::AddAtEnd and TagList::AddAtStart to update + * the byte offsets of each tag in the TagList. + * + * - whenever bytes are removed from the packet byte buffer, the TagList offsets + * are never updated because we rely on the fact that they will be updated in + * either the next call to Packet::AddHeader or Packet::AddTrailer or when + * the user iterates the tag list with Packet::GetTagIterator and + * TagIterator::Next. + */ +class TagList +{ +public: + + class Iterator + { + public: + struct Item + { + TypeId tid; + uint32_t size; + uint32_t start; + uint32_t end; + TagBuffer buf; + Item (TagBuffer buf); + private: + friend class TagList; + friend class TagList::Iterator; + }; + bool HasNext (void) const; + struct TagList::Iterator::Item Next (void); + uint32_t GetOffsetStart (void) const; + private: + friend class TagList; + Iterator (uint8_t *start, uint8_t *end, uint32_t offsetStart, uint32_t offsetEnd); + void PrepareForNext (void); + uint8_t *m_current; + uint8_t *m_end; + uint32_t m_offsetStart; + uint32_t m_offsetEnd; + uint32_t m_nextTid; + uint32_t m_nextSize; + uint32_t m_nextStart; + uint32_t m_nextEnd; + }; + + TagList (); + TagList (const TagList &o); + TagList &operator = (const TagList &o); + ~TagList (); + + /** + * \param tid the typeid of the tag added + * \param bufferSize the size of the tag when its serialization will + * be completed. Typically, the return value of Tag::GetSerializedSize + * \param start offset which uniquely identifies the first byte tagged by this tag. + * \param start offset which uniquely identifies the last byte tagged by this tag. + * \returns a buffer which can be used to write the tag data. + * + * + */ + TagBuffer Add (TypeId tid, uint32_t bufferSize, uint32_t start, uint32_t end); + + /** + * \param o the other list of tags to aggregate. + * + * Aggregate the two lists of tags. + */ + void Add (const TagList &o); + + /** + * \param i points to the item to remove from this list. + * + * Not implemented. + */ + void Remove (const Iterator &i); + void RemoveAll (void); + + /** + * \param offsetStart the offset which uniquely identifies the first data byte + * present in the byte buffer associated to this TagList. + * \param offsetEnd the offset which uniquely identifies the last data byte + * present in the byte buffer associated to this TagList. + * \returns an iterator + * + * The returned iterator will allow you to loop through the set of tags present + * in this list: the boundaries of each tag as reported by their start and + * end offsets will be included within the input offsetStart and offsetEnd. + */ + TagList::Iterator Begin (uint32_t offsetStart, uint32_t offsetEnd) const; + + /** + * Adjust the offsets stored internally by the adjustment delta and + * make sure that all offsets are smaller than appendOffset which represents + * the location where new bytes have been added to the byte buffer. + */ + void AddAtEnd (int32_t adjustment, uint32_t appendOffset); + /** + * Adjust the offsets stored internally by the adjustment delta and + * make sure that all offsets are bigger than prependOffset which represents + * the location where new bytes have been added to the byte buffer. + */ + void AddAtStart (int32_t adjustment, uint32_t prependOffset); + +private: + bool IsDirtyAtEnd (uint32_t appendOffset); + bool IsDirtyAtStart (uint32_t prependOffset); + + struct TagListData *Allocate (uint32_t size); + void Deallocate (struct TagListData *data); + + uint16_t m_used; + struct TagListData *m_data; +}; + +} // namespace ns3 + +#endif /* TAG_LIST_H */ diff --git a/src/common/tag-registry.cc b/src/common/tag-registry.cc deleted file mode 100644 index 01ae31fbc..000000000 --- a/src/common/tag-registry.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2006 INRIA - * - * 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 - */ -#include "tag-registry.h" -#include "ns3/fatal-error.h" - -namespace ns3 { - -TagRegistry::TagInfoVector * -TagRegistry::GetInfo (void) -{ - static TagRegistry::TagInfoVector vector; - return &vector; -} - -std::string -TagRegistry::GetUidString (uint32_t uid) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - return info.uidString; -} -uint32_t -TagRegistry::GetUidFromUidString (std::string uidString) -{ - TagInfoVector *vec = GetInfo (); - uint32_t uid = 1; - for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++) - { - if (i->uidString == uidString) - { - return uid; - } - uid++; - } - NS_FATAL_ERROR ("We are trying to deserialize an un-registered type. This can't work."); - return 0; -} - -void -TagRegistry::Destruct (uint32_t uid, uint8_t *data) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - info.destruct (data); -} -void -TagRegistry::Print (uint32_t uid, uint8_t *data, std::ostream &os) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - info.print (data, os); -} -uint32_t -TagRegistry::GetSerializedSize (uint32_t uid, uint8_t *data) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - return info.getSerializedSize (data); -} -void -TagRegistry::Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - info.serialize (data, start); -} -uint32_t -TagRegistry::Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - return info.deserialize (data, start); -} - -} // namespace ns3 diff --git a/src/common/tag-registry.h b/src/common/tag-registry.h deleted file mode 100644 index 52d16f281..000000000 --- a/src/common/tag-registry.h +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2006 INRIA - * - * 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 - */ -#ifndef TAG_REGISTRY_H -#define TAG_REGISTRY_H - -#include -#include -#include "buffer.h" - -namespace ns3 { - -/** - * \brief a registry of all existing tag types. - * \internal - * - * This class is used to give polymorphic access to the methods - * exported by a tag. It also is used to associate a single - * reliable uid to each unique type. - */ -class TagRegistry -{ -public: - template - static uint32_t Register (std::string uidString); - static std::string GetUidString (uint32_t uid); - static uint32_t GetUidFromUidString (std::string uidString); - static void Destruct (uint32_t uid, uint8_t *data); - static void Print (uint32_t uid, uint8_t *data, std::ostream &os); - static uint32_t GetSerializedSize (uint32_t uid, uint8_t *data); - static void Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start); - static uint32_t Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start); -private: - typedef void (*DestructCb) (uint8_t *); - typedef void (*PrintCb) (uint8_t *, std::ostream &); - typedef uint32_t (*GetSerializedSizeCb) (uint8_t *); - typedef void (*SerializeCb) (uint8_t *, Buffer::Iterator); - typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator); - struct TagInfo - { - std::string uidString; - DestructCb destruct; - PrintCb print; - GetSerializedSizeCb getSerializedSize; - SerializeCb serialize; - DeserializeCb deserialize; - }; - typedef std::vector TagInfoVector; - - template - static void DoDestruct (uint8_t *data); - template - static void DoPrint (uint8_t *data, std::ostream &os); - template - static uint32_t DoGetSerializedSize (uint8_t *data); - template - static void DoSerialize (uint8_t *data, Buffer::Iterator start); - template - static uint32_t DoDeserialize (uint8_t *data, Buffer::Iterator start); - - static TagInfoVector *GetInfo (void); -}; - -} // namespace ns3 - -namespace ns3 { - -template -void -TagRegistry::DoDestruct (uint8_t *data) -{ - T *tag = reinterpret_cast (data); - tag->~T (); -} -template -void -TagRegistry::DoPrint (uint8_t *data, std::ostream &os) -{ - T *tag = reinterpret_cast (data); - tag->Print (os); -} -template -uint32_t -TagRegistry::DoGetSerializedSize (uint8_t *data) -{ - T *tag = reinterpret_cast (data); - return tag->GetSerializedSize (); -} -template -void -TagRegistry::DoSerialize (uint8_t *data, Buffer::Iterator start) -{ - T *tag = reinterpret_cast (data); - tag->Serialize (start); -} -template -uint32_t -TagRegistry::DoDeserialize (uint8_t *data, Buffer::Iterator start) -{ - T *tag = reinterpret_cast (data); - return tag->Deserialize (start); -} - -template -uint32_t -TagRegistry::Register (std::string uidString) -{ - TagInfoVector *vec = GetInfo (); - uint32_t j = 0; - for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++) - { - if (i->uidString == uidString) - { - return j; - } - j++; - } - TagInfo info; - info.uidString = uidString; - info.destruct = &TagRegistry::DoDestruct; - info.print = &TagRegistry::DoPrint; - info.getSerializedSize = &TagRegistry::DoGetSerializedSize; - info.serialize = &TagRegistry::DoSerialize; - info.deserialize = &TagRegistry::DoDeserialize; - vec->push_back (info); - uint32_t uid = vec->size (); - return uid; -} - -} // namespace ns3 - -#endif /* TAG_REGISTRY_H */ diff --git a/src/mobility/mobility-model-notifier.cc b/src/common/tag.cc similarity index 53% rename from src/mobility/mobility-model-notifier.cc rename to src/common/tag.cc index 026207137..c561dcb9c 100644 --- a/src/mobility/mobility-model-notifier.cc +++ b/src/common/tag.cc @@ -1,6 +1,6 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* - * Copyright (c) 2007 INRIA + * Copyright (c) 2008 INRIA * * 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 @@ -17,31 +17,18 @@ * * Author: Mathieu Lacage */ -#include "mobility-model-notifier.h" -#include "ns3/trace-source-accessor.h" +#include "tag.h" namespace ns3 { TypeId -MobilityModelNotifier::GetTypeId (void) +Tag::GetTypeId (void) { - static TypeId tid = TypeId ("MobilityModelNotifier") - .SetParent () - .AddConstructor () - .AddTraceSource ("CourseChange", - "The value of the position and/or velocity vector changed", - MakeTraceSourceAccessor (&MobilityModelNotifier::m_trace)) + static TypeId tid = TypeId ("ns3::Tag") + .SetParent () ; return tid; } -MobilityModelNotifier::MobilityModelNotifier () -{} - -void -MobilityModelNotifier::Notify (Ptr position) const -{ - m_trace (position); -} } // namespace ns3 diff --git a/src/common/tag.h b/src/common/tag.h index b07f78206..c4191864d 100644 --- a/src/common/tag.h +++ b/src/common/tag.h @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* - * Copyright (c) 2006 INRIA + * Copyright (c) 2008 INRIA * * 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 @@ -20,106 +20,43 @@ #ifndef TAG_H #define TAG_H +#include "ns3/object-base.h" +#include "tag-buffer.h" #include -#include - -/** - * \relates ns3::Tag - * \brief this macro should be instantiated exactly once for each - * new type of Tag - * - * This macro will ensure that your new Tag type is registered - * within the tag registry. In most cases, this macro - * is not really needed but, for safety, please, use it all the - * time. - * - * Note: This macro is _absolutely_ needed if you try to run a - * distributed simulation. - */ -#define NS_TAG_ENSURE_REGISTERED(x) \ -static class thisisaveryverylongclassname ##x \ -{ \ - public: \ - thisisaveryverylongclassname ##x () \ - { uint32_t uid; uid = x::GetUid ();} \ -} g_thisisanotherveryveryverylongname ## x; namespace ns3 { /** - * \brief a tag can be stored in a packet. + * \brief tag a set of bytes in a packet * - * A tag is a blob of 16 bytes of data which can be stored in - * a packet: a packet can contain an arbitrary number of tags - * and these tags are considered as "on-the-side" per-packet - * data structures which are not taken into account when calculating - * the size of the payload of a packet. They exist solely as - * simulation-specific objects. - * - * Tags are typically used to: - * - implement per-packet cross-layer communication - * - implement packet coloring: you could store a "color" tag - * in a packet to mark various types of packet for - * simulation analysis - * - * To create a new type of tag, you must create a subclass - * of the Tag base class which defines: - * - a public default constructor: needed for implementation - * purposes of the Packet code. - * - a public copy constructor: needed to copy a tag into - * a packet tag buffer when the user invokes Packet::AddTag - * - a public destructor: needed to destroy the copy of a tag - * stored in a packet buffer when the user invokes Packet::RemoveTag - * or when the packet is destroyed and the last reference to - * a tag instance disapears. - * - a public static method named GetUid: needed to uniquely - * the type of each tag instance. - * - a public method named Print: needed to print the content - * of a tag when the user calls Packet::PrintTags - * - a public method named GetSerializedSize: needed to serialize - * the content of a tag to a byte buffer when a packet must - * be sent from one computing node to another in a parallel - * simulation. If this method returns 0, it means that the - * tag does not need to be transfered from computing node to - * computing node - * - a public method named Serialize: perform the serialization - * to a byte buffer upon transfer to a new computing node in a - * parallel simulation. - * - a public method named Deserialize: invert the serialization - * from a byte buffer after being transfered to a new computing - * node in a parallel simulation. - * - * A detailed example of what these methods should look like - * and how they should be implemented is described in samples/main-packet-tag.cc + * New kinds of tags can be created by subclassing this base class. */ -class Tag +class Tag : public ObjectBase { -protected: +public: + static TypeId GetTypeId (void); + /** - * \param name the unique name of the new type of tag - * \returns a newly-allocated uid + * \returns the number of bytes required to serialize the data of the tag. * - * This method should be used by subclasses to implement - * their static public GetUid method. + * This method is typically invoked by Packet::AddTag just prior to calling + * Tag::Serialize. */ - template - static uint32_t AllocateUid (std::string name); + virtual uint32_t GetSerializedSize (void) const = 0; + /** + * \param i the buffer to write data into. + * + * Write the content of the tag in the provided tag buffer. + */ + virtual void Serialize (TagBuffer i) const = 0; + /** + * \param i the buffer to read data from. + * + * Read the content of the tag from the provided tag buffer. + */ + virtual void Deserialize (TagBuffer i) = 0; }; } // namespace ns3 -// implementation below. -#include "tag-registry.h" - -namespace ns3 { - -template -uint32_t -Tag::AllocateUid (std::string name) -{ - return TagRegistry::Register (name); -} - -} // namespace ns3 - #endif /* TAG_H */ diff --git a/src/common/tags.cc b/src/common/tags.cc deleted file mode 100644 index a719417a4..000000000 --- a/src/common/tags.cc +++ /dev/null @@ -1,529 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2006 INRIA - * - * 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 - */ -#include "tags.h" -#include -#include "ns3/fatal-error.h" - -namespace ns3 { - -#ifdef USE_FREE_LIST - -struct Tags::TagData *Tags::gFree = 0; -uint32_t Tags::gN_free = 0; - -struct Tags::TagData * -Tags::AllocData (void) const -{ - struct Tags::TagData *retval; - if (gFree != 0) - { - retval = gFree; - gFree = gFree->m_next; - gN_free--; - } - else - { - retval = new struct Tags::TagData (); - } - return retval; -} - -void -Tags::FreeData (struct TagData *data) const -{ - if (gN_free > 1000) - { - delete data; - return; - } - gN_free++; - data->m_next = gFree; - data->m_id = 0; - gFree = data; -} -#else -struct Tags::TagData * -Tags::AllocData (void) const -{ - struct Tags::TagData *retval; - retval = new struct Tags::TagData (); - return retval; -} - -void -Tags::FreeData (struct TagData *data) const -{ - delete data; -} -#endif - -bool -Tags::Remove (uint32_t id) -{ - bool found = false; - for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) - { - if (cur->m_id == id) - { - found = true; - } - } - if (!found) - { - return false; - } - struct TagData *start = 0; - struct TagData **prevNext = &start; - for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) - { - if (cur->m_id == id) - { - /** - * XXX - * Note: I believe that we could optimize this to - * avoid copying each TagData located after the target id - * and just link the already-copied list to the next tag. - */ - continue; - } - struct TagData *copy = AllocData (); - copy->m_id = cur->m_id; - copy->m_count = 1; - copy->m_next = 0; - memcpy (copy->m_data, cur->m_data, Tags::SIZE); - *prevNext = copy; - prevNext = ©->m_next; - } - *prevNext = 0; - RemoveAll (); - m_next = start; - return true; -} - -void -Tags::Print (std::ostream &os, std::string separator) const -{ - for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) - { - TagRegistry::Print (cur->m_id, cur->m_data, os); - if (cur->m_next != 0) - { - os << separator; - } - } -} - -uint32_t -Tags::GetSerializedSize (void) const -{ - uint32_t totalSize = 4; // reserve space for the size of the tag data. - for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) - { - uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data); - if (size != 0) - { - std::string uidString = TagRegistry::GetUidString (cur->m_id); - totalSize += 4; // for the size of the string itself. - totalSize += uidString.size (); - totalSize += size; - } - } - return totalSize; -} - -void -Tags::Serialize (Buffer::Iterator i, uint32_t totalSize) const -{ - i.WriteU32 (totalSize); - for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) - { - uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data); - if (size != 0) - { - std::string uidString = TagRegistry::GetUidString (cur->m_id); - i.WriteU32 (uidString.size ()); - uint8_t *buf = (uint8_t *)uidString.c_str (); - i.Write (buf, uidString.size ()); - TagRegistry::Serialize (cur->m_id, cur->m_data, i); - } - } -} -uint32_t -Tags::Deserialize (Buffer::Iterator i) -{ - uint32_t totalSize = i.ReadU32 (); - uint32_t bytesRead = 4; - while (bytesRead < totalSize) - { - uint32_t uidStringSize = i.ReadU32 (); - bytesRead += 4; - std::string uidString; - uidString.reserve (uidStringSize); - for (uint32_t j = 0; j < uidStringSize; j++) - { - uint32_t c = i.ReadU8 (); - uidString.push_back (c); - } - bytesRead += uidStringSize; - uint32_t uid = TagRegistry::GetUidFromUidString (uidString); - struct TagData *newStart = AllocData (); - newStart->m_count = 1; - newStart->m_next = 0; - newStart->m_id = uid; - bytesRead += TagRegistry::Deserialize (uid, newStart->m_data, i); - newStart->m_next = m_next; - m_next = newStart; - } - NS_ASSERT (bytesRead == totalSize); - /** - * The process of serialization/deserialization - * results in an inverted linked-list after - * deserialization so, we invert the linked-list - * in-place here. - * Note: the algorithm below is pretty classic - * but whenever I get to code it, it makes my - * brain hurt :) - */ - struct TagData *prev = 0; - struct TagData *cur = m_next; - while (cur != 0) - { - struct TagData *next = cur->m_next; - cur->m_next = prev; - prev = cur; - cur = next; - } - m_next = prev; - return totalSize; -} - - - -}; // namespace ns3 - -#ifdef RUN_SELF_TESTS - -#include "ns3/test.h" -#include -#include - -namespace ns3 { - -static bool g_a; -static bool g_b; -static bool g_c; -static bool g_z; - -class TagsTest : Test { -public: - TagsTest (); - virtual ~TagsTest (); - virtual bool RunTests (void); -}; - -class myTagA : public Tag -{ -public: - static uint32_t GetUid (void) {static uint32_t uid = AllocateUid ("myTagA.test.nsnam.org"); return uid;} - void Print (std::ostream &os) const {g_a = true;} - uint32_t GetSerializedSize (void) const {return 1;} - void Serialize (Buffer::Iterator i) const {i.WriteU8 (a);} - uint32_t Deserialize (Buffer::Iterator i) {a = i.ReadU8 (); return 1;} - - uint8_t a; -}; -class myTagB : public Tag -{ -public: - static uint32_t GetUid (void) {static uint32_t uid = AllocateUid ("myTagB.test.nsnam.org"); return uid;} - void Print (std::ostream &os) const {g_b = true;} - uint32_t GetSerializedSize (void) const {return 4;} - void Serialize (Buffer::Iterator i) const {i.WriteU32 (b);} - uint32_t Deserialize (Buffer::Iterator i) {b = i.ReadU32 (); return 4;} - - uint32_t b; -}; -class myTagC : public Tag -{ -public: - static uint32_t GetUid (void) {static uint32_t uid = AllocateUid ("myTagC.test.nsnam.org"); return uid;} - void Print (std::ostream &os) const {g_c = true;} - uint32_t GetSerializedSize (void) const {return Tags::SIZE;} - void Serialize (Buffer::Iterator i) const {i.Write (c, Tags::SIZE);} - uint32_t Deserialize (Buffer::Iterator i) {i.Read (c, Tags::SIZE); return Tags::SIZE;} - uint8_t c [Tags::SIZE]; -}; -class myInvalidTag : public Tag -{ -public: - static uint32_t GetUid (void) - {static uint32_t uid = AllocateUid ("myinvalidTag.test.nsnam.org"); return uid;} - void Print (std::ostream &os) const {} - uint32_t GetSerializedSize (void) const {return 0;} - void Serialize (Buffer::Iterator i) const {} - uint32_t Deserialize (Buffer::Iterator i) {return 0;} - - uint8_t invalid [Tags::SIZE+1]; -}; -class myTagZ : public Tag -{ -public: - static uint32_t GetUid (void) {static uint32_t uid = AllocateUid ("myTagZ.test.nsnam.org"); return uid;} - void Print (std::ostream &os) const {g_z = true;} - uint32_t GetSerializedSize (void) const {return 0;} - void Serialize (Buffer::Iterator i) const {} - uint32_t Deserialize (Buffer::Iterator i) {return 0;} - - uint8_t z; -}; - -class MySmartTag : public Tag -{ -public: - static uint32_t GetUid (void) - {static uint32_t uid = AllocateUid ("MySmartTag.test.nsnam.org"); return uid;} - MySmartTag () - { - //std::cout << "construct" << std::endl; - } - MySmartTag (const MySmartTag &o) - { - //std::cout << "copy" << std::endl; - } - ~MySmartTag () - { - //std::cout << "destruct" << std::endl; - } - MySmartTag &operator = (const MySmartTag &o) - { - //std::cout << "assign" << std::endl; - return *this; - } - void Print (std::ostream &os) const {} - uint32_t GetSerializedSize (void) const {return 0;} - void Serialize (Buffer::Iterator i) const {} - uint32_t Deserialize (Buffer::Iterator i) {return 0;} -}; - - -TagsTest::TagsTest () - : Test ("Tags") -{} -TagsTest::~TagsTest () -{} - -bool -TagsTest::RunTests (void) -{ - bool ok = true; - - // build initial tag. - Tags tags; - myTagA a; - a.a = 10; - tags.Add (a); - a.a = 0; - tags.Peek (a); - if (a.a != 10) - { - ok = false; - } - g_a = false; - tags.Print (std::cout, ""); - if (!g_a) - { - ok = false; - } - myTagB b; - b.b = 0xff; - tags.Add (b); - b.b = 0; - tags.Peek (b); - if (b.b != 0xff) - { - ok = false; - } - g_b = false; - g_a = false; - tags.Print (std::cout, ""); - if (!g_a || !g_b) - { - ok = false; - } - // make sure copy contains copy. - Tags other = tags; - g_b = false; - g_a = false; - other.Print (std::cout, ""); - if (!g_a || !g_b) - { - ok = false; - } - g_b = false; - g_a = false; - tags.Print (std::cout, ""); - if (!g_a || !g_b) - { - ok = false; - } - myTagA oA; - oA.a = 0; - other.Peek (oA); - if (oA.a != 10) - { - ok = false; - } - myTagB oB; - oB.b = 1; - other.Peek (oB); - if (oB.b != 0xff) - { - ok = false; - } - // remove data. - other.Remove (oA); - if (other.Peek (oA)) - { - ok = false; - } - g_b = false; - g_a = false; - other.Print (std::cout, ""); - if (g_a || !g_b) - { - ok = false; - } - if (!tags.Peek (oA)) - { - ok = false; - } - other.Remove (oB); - if (other.Peek (oB)) - { - ok = false; - } - if (!tags.Peek (oB)) - { - ok = false; - } - - other = tags; - Tags another = other; - myTagC c; - memset (c.c, 0x66, 16); - another.Add (c); - c.c[0] = 0; - another.Peek (c); - if (!another.Peek (c)) - { - ok = false; - } - if (tags.Peek (c)) - { - ok = false; - } - - other = other; - //other.prettyPrint (std::cout); - - //struct myInvalidTag invalid; - //tags.add (&invalid); - - myTagZ tagZ; - Tags testLastTag; - tagZ.z = 0; - testLastTag.Add (tagZ); - g_z = false; - testLastTag.Print (std::cout, ""); - if (!g_z) - { - ok = false; - } - - MySmartTag smartTag; - { - Tags tmp; - tmp.Add (smartTag); - tmp.Peek (smartTag); - tmp.Remove (smartTag); - } - - { - Tags source; - myTagA aSource; - aSource.a = 0x66; - source.Add (aSource); - Buffer buffer; - uint32_t serialized = source.GetSerializedSize (); - buffer.AddAtStart (serialized); - source.Serialize (buffer.Begin (), serialized); - Tags dest; - dest.Deserialize (buffer.Begin ()); - myTagA aDest; - aDest.a = 0x55; - dest.Peek (aDest); - if (aDest.a != 0x66) - { - ok = false; - } - } - - { - Tags source; - myTagA aSource; - aSource.a = 0x66; - source.Add (aSource); - myTagZ zSource; - zSource.z = 0x77; - source.Add (zSource); - - Buffer buffer; - uint32_t serialized = source.GetSerializedSize (); - buffer.AddAtStart (serialized); - source.Serialize (buffer.Begin (), serialized); - Tags dest; - dest.Deserialize (buffer.Begin ()); - - myTagA aDest; - aDest.a = 0x55; - dest.Peek (aDest); - if (aDest.a != 0x66) - { - ok = false; - } - myTagZ zDest; - zDest.z = 0x44; - dest.Peek (zDest); - if (zDest.z != 0x44) - { - ok = false; - } - } - - return ok; -} - -static TagsTest gTagsTest; - - -}; // namespace ns3 - -#endif /* RUN_SELF_TESTS */ - diff --git a/src/common/tags.h b/src/common/tags.h deleted file mode 100644 index d8ca513b5..000000000 --- a/src/common/tags.h +++ /dev/null @@ -1,228 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2006 INRIA - * - * 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 - */ -#ifndef TAGS_H -#define TAGS_H - -#include -#include -#include -#include "buffer.h" - -namespace ns3 { - -/** - * \ingroup constants - * \brief Tag maximum size - * The maximum size (in bytes) of a Tag is stored - * in this constant. - */ -#define TAGS_MAX_SIZE 32 - -class Tags { -public: - inline Tags (); - inline Tags (Tags const &o); - inline Tags &operator = (Tags const &o); - inline ~Tags (); - - template - void Add (T const&tag) const; - - template - bool Remove (T &tag); - - template - bool Peek (T &tag) const; - - void Print (std::ostream &os, std::string separator) const; - uint32_t GetSerializedSize (void) const; - void Serialize (Buffer::Iterator i, uint32_t size) const; - uint32_t Deserialize (Buffer::Iterator i); - - inline void RemoveAll (void); - - enum { - SIZE = TAGS_MAX_SIZE - }; -private: - struct TagData { - uint8_t m_data[Tags::SIZE]; - struct TagData *m_next; - uint32_t m_id; - uint32_t m_count; - }; - - bool Remove (uint32_t id); - struct Tags::TagData *AllocData (void) const; - void FreeData (struct TagData *data) const; - - static struct Tags::TagData *gFree; - static uint32_t gN_free; - - struct TagData *m_next; -}; - -} // namespace ns3 - - - -/************************************************************** - An implementation of the templates defined above - *************************************************************/ -#include "tag-registry.h" -#include "tag.h" -#include "ns3/assert.h" -#include - -namespace ns3 { - -template -void -Tags::Add (T const&tag) const -{ - const Tag *parent; - // if the following assignment fails, it is because the - // input to this function is not a subclass of the Tag class. - parent = &tag; - - NS_ASSERT (sizeof (T) <= Tags::SIZE); - // ensure this id was not yet added - for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) - { - NS_ASSERT (cur->m_id != T::GetUid ()); - } - struct TagData *newStart = AllocData (); - newStart->m_count = 1; - newStart->m_next = 0; - newStart->m_id = T::GetUid (); - void *buf = &newStart->m_data; - new (buf) T (tag); - newStart->m_next = m_next; - const_cast (this)->m_next = newStart; -} - -template -bool -Tags::Remove (T &tag) -{ - Tag *parent; - // if the following assignment fails, it is because the - // input to this function is not a subclass of the Tag class. - parent = &tag; - NS_ASSERT (sizeof (T) <= Tags::SIZE); - if (Peek (tag)) - { - Remove (T::GetUid ()); - return true; - } - else - { - return false; - } -} - -template -bool -Tags::Peek (T &tag) const -{ - Tag *parent; - // if the following assignment fails, it is because the - // input to this function is not a subclass of the Tag class. - parent = &tag; - NS_ASSERT (sizeof (T) <= Tags::SIZE); - for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) - { - if (cur->m_id == T::GetUid ()) - { - /* found tag */ - T *data = reinterpret_cast (&cur->m_data); - tag = T (*data); - return true; - } - } - /* no tag found */ - return false; -} - -Tags::Tags () - : m_next () -{} - -Tags::Tags (Tags const &o) - : m_next (o.m_next) -{ - if (m_next != 0) - { - m_next->m_count++; - } -} - -Tags & -Tags::operator = (Tags const &o) -{ - // self assignment - if (m_next == o.m_next) - { - return *this; - } - RemoveAll (); - m_next = o.m_next; - if (m_next != 0) - { - m_next->m_count++; - } - return *this; -} - -Tags::~Tags () -{ - RemoveAll (); -} - -void -Tags::RemoveAll (void) -{ - struct TagData *prev = 0; - for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) - { - cur->m_count--; - if (cur->m_count > 0) - { - break; - } - if (prev != 0) - { - TagRegistry::Destruct (prev->m_id, prev->m_data); - FreeData (prev); - } - prev = cur; - } - if (prev != 0) - { - TagRegistry::Destruct (prev->m_id, prev->m_data); - FreeData (prev); - } - m_next = 0; -} - - -}; // namespace ns3 - -#endif /* TAGS_H */ diff --git a/src/common/wscript b/src/common/wscript index 89db5ace1..0b76283bf 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -7,14 +7,15 @@ def build(bld): 'packet-metadata.cc', 'packet-metadata-test.cc', 'packet.cc', - 'tags.cc', - 'tag-registry.cc', 'chunk.cc', 'header.cc', 'trailer.cc', 'pcap-writer.cc', 'data-rate.cc', 'error-model.cc', + 'tag.cc', + 'tag-list.cc', + 'tag-buffer.cc', ] headers = bld.create_obj('ns3header') @@ -24,12 +25,12 @@ def build(bld): 'chunk.h', 'header.h', 'trailer.h', - 'tags.h', - 'tag-registry.h', - 'tag.h', 'packet.h', 'packet-metadata.h', 'pcap-writer.h', 'data-rate.h', 'error-model.h', + 'tag.h', + 'tag-list.h', + 'tag-buffer.h', ] diff --git a/src/contrib/attribute-iterator.cc b/src/contrib/attribute-iterator.cc new file mode 100644 index 000000000..8a6b02b3d --- /dev/null +++ b/src/contrib/attribute-iterator.cc @@ -0,0 +1,274 @@ +#include "attribute-iterator.h" +#include "ns3/config.h" +#include "ns3/log.h" +#include "ns3/pointer.h" +#include "ns3/object-vector.h" +#include "ns3/string.h" +#include + + +NS_LOG_COMPONENT_DEFINE ("AttributeIterator"); + +namespace ns3 { + + +AttributeIterator::AttributeIterator () +{} + +AttributeIterator::~AttributeIterator () +{} + +void +AttributeIterator::Iterate (void) +{ + for (uint32_t i = 0; i < Config::GetRootNamespaceObjectN (); ++i) + { + Ptr object = Config::GetRootNamespaceObject (i); + StartVisitObject (object); + DoIterate (object); + EndVisitObject (); + } + NS_ASSERT (m_currentPath.empty ()); + NS_ASSERT (m_examined.empty ()); +} + +bool +AttributeIterator::IsExamined (Ptr object) +{ + for (uint32_t i = 0; i < m_examined.size (); ++i) + { + if (object == m_examined[i]) + { + return true; + } + } + return false; +} + + +std::string +AttributeIterator::GetCurrentPath (std::string attr) const +{ + std::ostringstream oss; + for (uint32_t i = 0; i < m_currentPath.size (); ++i) + { + oss << "/" << m_currentPath[i]; + } + if (attr != "") + { + oss << "/" << attr; + } + return oss.str (); +} + +std::string +AttributeIterator::GetCurrentPath (void) const +{ + std::ostringstream oss; + for (uint32_t i = 0; i < m_currentPath.size (); ++i) + { + oss << "/" << m_currentPath[i]; + } + return oss.str (); +} + +void +AttributeIterator::DoStartVisitObject (Ptr object) +{} +void +AttributeIterator::DoEndVisitObject (void) +{} +void +AttributeIterator::DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr item) +{} +void +AttributeIterator::DoEndVisitPointerAttribute (void) +{} +void +AttributeIterator::DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector) +{} +void +AttributeIterator::DoEndVisitArrayAttribute (void) +{} +void +AttributeIterator::DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item) +{} +void +AttributeIterator::DoEndVisitArrayItem (void) +{} + +void +AttributeIterator::VisitAttribute (Ptr object, std::string name) +{ + m_currentPath.push_back (name); + DoVisitAttribute (object, name); + m_currentPath.pop_back (); +} + +void +AttributeIterator::StartVisitObject (Ptr object) +{ + m_currentPath.push_back ("$" + object->GetInstanceTypeId ().GetName ()); + DoStartVisitObject (object); +} +void +AttributeIterator::EndVisitObject (void) +{ + m_currentPath.pop_back (); + DoEndVisitObject (); +} +void +AttributeIterator::StartVisitPointerAttribute (Ptr object, std::string name, Ptr value) +{ + m_currentPath.push_back (name); + m_currentPath.push_back ("$" + value->GetInstanceTypeId ().GetName ()); + DoStartVisitPointerAttribute (object, name, value); +} +void +AttributeIterator::EndVisitPointerAttribute (void) +{ + m_currentPath.pop_back (); + m_currentPath.pop_back (); + DoEndVisitPointerAttribute (); +} +void +AttributeIterator::StartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector) +{ + m_currentPath.push_back (name); + DoStartVisitArrayAttribute (object, name, vector); +} +void +AttributeIterator::EndVisitArrayAttribute (void) +{ + m_currentPath.pop_back (); + DoEndVisitArrayAttribute (); +} + +void +AttributeIterator::StartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item) +{ + std::ostringstream oss; + oss << index; + m_currentPath.push_back (oss.str ()); + m_currentPath.push_back ("$" + item->GetInstanceTypeId ().GetName ()); + DoStartVisitArrayItem (vector, index, item); +} +void +AttributeIterator::EndVisitArrayItem (void) +{ + m_currentPath.pop_back (); + m_currentPath.pop_back (); + DoEndVisitArrayItem (); +} + + +void +AttributeIterator::DoIterate (Ptr object) +{ + if (IsExamined (object)) + { + return; + } + TypeId tid; + for (tid = object->GetInstanceTypeId (); tid.HasParent (); tid = tid.GetParent ()) + { + NS_LOG_DEBUG ("store " << tid.GetName ()); + for (uint32_t i = 0; i < tid.GetAttributeN (); ++i) + { + Ptr checker = tid.GetAttributeChecker (i); + const PointerChecker *ptrChecker = dynamic_cast (PeekPointer (checker)); + if (ptrChecker != 0) + { + NS_LOG_DEBUG ("pointer attribute " << tid.GetAttributeName (i)); + PointerValue ptr; + object->GetAttribute (tid.GetAttributeName (i), ptr); + Ptr tmp = ptr.Get (); + if (tmp != 0) + { + StartVisitPointerAttribute (object, tid.GetAttributeName (i), tmp); + m_examined.push_back (object); + DoIterate (tmp); + m_examined.pop_back (); + EndVisitPointerAttribute (); + } + continue; + } + // attempt to cast to an object vector. + const ObjectVectorChecker *vectorChecker = dynamic_cast (PeekPointer (checker)); + if (vectorChecker != 0) + { + NS_LOG_DEBUG ("vector attribute " << tid.GetAttributeName (i)); + ObjectVectorValue vector; + object->GetAttribute (tid.GetAttributeName (i), vector); + StartVisitArrayAttribute (object, tid.GetAttributeName (i), vector); + for (uint32_t j = 0; j < vector.GetN (); ++j) + { + NS_LOG_DEBUG ("vector attribute item " << j); + Ptr tmp = vector.Get (j); + StartVisitArrayItem (vector, j, tmp); + m_examined.push_back (object); + DoIterate (tmp); + m_examined.pop_back (); + EndVisitArrayItem (); + } + EndVisitArrayAttribute (); + continue; + } + uint32_t flags = tid.GetAttributeFlags (i); + Ptr accessor = tid.GetAttributeAccessor (i); + if ((flags & TypeId::ATTR_GET) && accessor->HasGetter () && + (flags & TypeId::ATTR_SET) && accessor->HasSetter ()) + { + VisitAttribute (object, tid.GetAttributeName (i)); + } + else + { + NS_LOG_DEBUG ("could not store " << tid.GetAttributeName (i)); + } + } + } + Object::AggregateIterator iter = object->GetAggregateIterator (); + bool recursiveAggregate = false; + while (iter.HasNext ()) + { + Ptr tmp = iter.Next (); + if (IsExamined (tmp)) + { + recursiveAggregate = true; + } + } + if (!recursiveAggregate) + { + iter = object->GetAggregateIterator (); + while (iter.HasNext ()) + { + Ptr tmp = const_cast (PeekPointer (iter.Next ())); + StartVisitObject (tmp); + m_examined.push_back (object); + DoIterate (tmp); + m_examined.pop_back (); + EndVisitObject (); + } + } +} + +TextFileAttributeIterator::TextFileAttributeIterator (std::ostream &os) + : m_os (os) +{} +void +TextFileAttributeIterator::DoVisitAttribute (Ptr object, std::string name) +{ + StringValue str; + object->GetAttribute (name, str); + m_os << GetCurrentPath () << " " << str.Get () << std::endl; +} + +void +TextFileAttributeIterator::Save (void) +{ + Iterate (); +} + + + +} // namespace ns3 diff --git a/src/contrib/attribute-iterator.h b/src/contrib/attribute-iterator.h new file mode 100644 index 000000000..b774b2e3f --- /dev/null +++ b/src/contrib/attribute-iterator.h @@ -0,0 +1,64 @@ +#ifndef ATTRIBUTE_ITERATOR_H +#define ATTRIBUTE_ITERATOR_H + +#include "ns3/ptr.h" +#include "ns3/object.h" +#include + +namespace ns3 { + +class ObjectVectorValue; + +class AttributeIterator +{ +public: + AttributeIterator (); + virtual ~AttributeIterator (); + + void Iterate (void); +protected: + std::string GetCurrentPath (void) const; +private: + virtual void DoVisitAttribute (Ptr object, std::string name) = 0; + virtual void DoStartVisitObject (Ptr object); + virtual void DoEndVisitObject (void); + virtual void DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr value); + virtual void DoEndVisitPointerAttribute (void); + virtual void DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector); + virtual void DoEndVisitArrayAttribute (void); + virtual void DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item); + virtual void DoEndVisitArrayItem (void); + + void DoIterate (Ptr object); + bool IsExamined (Ptr object); + std::string GetCurrentPath (std::string attr) const; + + void VisitAttribute (Ptr object, std::string name); + void StartVisitObject (Ptr object); + void EndVisitObject (void); + void StartVisitPointerAttribute (Ptr object, std::string name, Ptr value); + void EndVisitPointerAttribute (void); + void StartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector); + void EndVisitArrayAttribute (void); + void StartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item); + void EndVisitArrayItem (void); + + + std::vector > m_examined; + std::vector m_currentPath; +}; + +class TextFileAttributeIterator : public AttributeIterator +{ +public: + TextFileAttributeIterator (std::ostream &os); + void Save (void); +private: + virtual void DoVisitAttribute (Ptr object, std::string name); + std::ostream &m_os; +}; + + +} // namespace ns3 + +#endif /* ATTRIBUTE_ITERATOR_H */ diff --git a/src/contrib/config-store.cc b/src/contrib/config-store.cc index b07fb5282..55f9d7070 100644 --- a/src/contrib/config-store.cc +++ b/src/contrib/config-store.cc @@ -1,9 +1,9 @@ #include "config-store.h" +#include "attribute-iterator.h" #include "ns3/string.h" -#include "ns3/config.h" -#include "ns3/object-vector.h" -#include "ns3/pointer.h" #include "ns3/log.h" +#include "ns3/attribute-list.h" +#include "ns3/config.h" #include #include #include @@ -54,141 +54,22 @@ ConfigStore::LoadFrom (std::string filename) while (is.good()) { is >> path >> value; - NS_LOG_DEBUG (path << "=" << value); + NS_LOG_DEBUG (path << " " << value); Config::Set (path, StringValue (value)); } } void ConfigStore::StoreTo (std::string filename) { + std::ofstream os; os.open (filename.c_str (), std::ios::out); - for (uint32_t i = 0; i < Config::GetRootNamespaceObjectN (); ++i) - { - Ptr object = Config::GetRootNamespaceObject (i); - Store (os, object); - } + TextFileAttributeIterator iter = TextFileAttributeIterator (os); + iter.Save (); os.close (); - NS_ASSERT (m_currentPath.empty ()); - NS_ASSERT (m_examined.empty ()); exit (0); } -bool -ConfigStore::IsExamined (Ptr object) -{ - for (uint32_t i = 0; i < m_examined.size (); ++i) - { - if (object == m_examined[i]) - { - return true; - } - } - return false; -} - -std::string -ConfigStore::GetCurrentPath (std::string attr) const -{ - std::ostringstream oss; - for (uint32_t i = 0; i < m_currentPath.size (); ++i) - { - oss << "/" << m_currentPath[i]; - } - oss << "/" << attr; - return oss.str (); -} - -void -ConfigStore::Store (std::ostream &os, Ptr object) -{ - if (IsExamined (object)) - { - return; - } - TypeId tid = object->GetInstanceTypeId (); - m_currentPath.push_back ("$" + tid.GetName ()); - NS_LOG_DEBUG ("store " << tid.GetName ()); - for (uint32_t i = 0; i < tid.GetAttributeN (); ++i) - { - Ptr checker = tid.GetAttributeChecker (i); - const PointerChecker *ptrChecker = dynamic_cast (PeekPointer (checker)); - if (ptrChecker != 0) - { - NS_LOG_DEBUG ("pointer attribute " << tid.GetAttributeName (i)); - PointerValue ptr; - object->GetAttribute (tid.GetAttributeName (i), ptr); - Ptr tmp = ptr.Get (); - if (tmp != 0) - { - m_currentPath.push_back (tid.GetAttributeName (i)); - m_examined.push_back (object); - Store (os, tmp); - m_examined.pop_back (); - m_currentPath.pop_back (); - } - continue; - } - // attempt to cast to an object vector. - const ObjectVectorChecker *vectorChecker = dynamic_cast (PeekPointer (checker)); - if (vectorChecker != 0) - { - NS_LOG_DEBUG ("vector attribute " << tid.GetAttributeName (i)); - ObjectVectorValue vector; - object->GetAttribute (tid.GetAttributeName (i), vector); - for (uint32_t j = 0; j < vector.GetN (); ++j) - { - NS_LOG_DEBUG ("vector attribute item " << j); - Ptr tmp = vector.Get (j); - std::ostringstream oss; - oss << tid.GetAttributeName (i) << "/" << j; - m_currentPath.push_back (oss.str ()); - m_examined.push_back (object); - Store (os, tmp); - m_examined.pop_back (); - m_currentPath.pop_back (); - } - continue; - } - uint32_t flags = tid.GetAttributeFlags (i); - Ptr accessor = tid.GetAttributeAccessor (i); - if ((flags & TypeId::ATTR_GET) && accessor->HasGetter () && - (flags & TypeId::ATTR_SET) && accessor->HasSetter ()) - { - StringValue str; - object->GetAttribute (tid.GetAttributeName (i), str); - os << GetCurrentPath (tid.GetAttributeName (i)) << " " << str.Get () << std::endl; - } - else - { - NS_LOG_DEBUG ("could not store " << tid.GetAttributeName (i)); - } - } - Object::AggregateIterator iter = object->GetAggregateIterator (); - bool recursiveAggregate = false; - while (iter.HasNext ()) - { - Ptr tmp = iter.Next (); - if (IsExamined (tmp)) - { - recursiveAggregate = true; - } - } - if (!recursiveAggregate) - { - iter = object->GetAggregateIterator (); - while (iter.HasNext ()) - { - Ptr tmp = iter.Next (); - m_examined.push_back (object); - Store (os, tmp); - m_examined.pop_back (); - } - } - m_currentPath.pop_back (); -} - - void ConfigStore::Configure (void) { diff --git a/src/contrib/config-store.h b/src/contrib/config-store.h index 03501cfc6..38b80f282 100644 --- a/src/contrib/config-store.h +++ b/src/contrib/config-store.h @@ -2,14 +2,26 @@ #define CONFIG_STORE_H #include "ns3/object-base.h" -#include "ns3/object.h" -#include namespace ns3 { /** * \brief Store and load simulation attribute configuration * + * While it is possible to generate a sample config file and lightly + * edit it to change a couple of values, there are cases where this + * process will not work because the same value on the same object + * can appear multiple times in the same automatically-generated + * configuration file under different configuration paths. + * + * As such, the best way to use this class is to use it to generate + * an initial configuration file, extract from that configuration + * file only the strictly necessary elements, and move these minimal + * elements to a new configuration file which can then safely + * be edited. Another option is to use the ns3::GtkConfigStore class + * which will allow you to edit the parameters and will generate + * configuration files where all the instances of the same parameter + * are changed. */ class ConfigStore : public ObjectBase { @@ -29,14 +41,9 @@ public: private: void LoadFrom (std::string filename); void StoreTo (std::string filename); - void Store (std::ostream &os, Ptr object); - bool IsExamined (Ptr object); - std::string GetCurrentPath (std::string attr) const; std::string m_loadFilename; std::string m_storeFilename; - std::vector > m_examined; - std::vector m_currentPath; }; } // namespace ns3 diff --git a/src/contrib/delay-jitter-estimation.cc b/src/contrib/delay-jitter-estimation.cc index 207855ee1..681a06587 100644 --- a/src/contrib/delay-jitter-estimation.cc +++ b/src/contrib/delay-jitter-estimation.cc @@ -2,60 +2,71 @@ #include "delay-jitter-estimation.h" #include "ns3/tag.h" #include "ns3/simulator.h" +#include "ns3/string.h" -namespace { +namespace ns3 { -class TimestampTag : public ns3::Tag +class DelayJitterEstimationTimestampTag : public Tag { public: - TimestampTag (); - static uint32_t GetUid (void); - void Print (std::ostream &os) const; - void Serialize (ns3::Buffer::Iterator start) const; - uint32_t Deserialize (ns3::Buffer::Iterator start); - uint32_t GetSerializedSize (void) const; + DelayJitterEstimationTimestampTag (); + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; - ns3::Time GetTxTime (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); + + + Time GetTxTime (void) const; private: uint64_t m_creationTime; }; -TimestampTag::TimestampTag () - : m_creationTime (ns3::Simulator::Now ().GetTimeStep ()) +DelayJitterEstimationTimestampTag::DelayJitterEstimationTimestampTag () + : m_creationTime (Simulator::Now ().GetTimeStep ()) {} -uint32_t -TimestampTag::GetUid (void) + +TypeId +DelayJitterEstimationTimestampTag::GetTypeId (void) { - static uint32_t uid = ns3::Tag::AllocateUid ("mathieu.paper.TimestampTag"); - return uid; + static TypeId tid = TypeId ("anon::DelayJitterEstimationTimestampTag") + .SetParent () + .AddConstructor () + .AddAttribute ("CreationTime", + "The time at which the timestamp was created", + StringValue ("0.0s"), + MakeTimeAccessor (&DelayJitterEstimationTimestampTag::GetTxTime), + MakeTimeChecker ()) + ; + return tid; } -void -TimestampTag::Print (std::ostream &os) const +TypeId +DelayJitterEstimationTimestampTag::GetInstanceTypeId (void) const { - os << ns3::TimeStep (m_creationTime); -} -void -TimestampTag::Serialize (ns3::Buffer::Iterator start) const -{} -uint32_t -TimestampTag::Deserialize (ns3::Buffer::Iterator start) -{ - return 0; -} -uint32_t -TimestampTag::GetSerializedSize (void) const -{ - return 0; -} -ns3::Time -TimestampTag::GetTxTime (void) const -{ - return ns3::TimeStep (m_creationTime); + return GetTypeId (); } +uint32_t +DelayJitterEstimationTimestampTag::GetSerializedSize (void) const +{ + return 8; +} +void +DelayJitterEstimationTimestampTag::Serialize (TagBuffer i) const +{ + i.WriteU64 (m_creationTime); +} +void +DelayJitterEstimationTimestampTag::Deserialize (TagBuffer i) +{ + m_creationTime = i.ReadU64 (); +} +Time +DelayJitterEstimationTimestampTag::GetTxTime (void) const +{ + return TimeStep (m_creationTime); } - -namespace ns3 { DelayJitterEstimation::DelayJitterEstimation () : m_previousRx (Simulator::Now ()), @@ -66,15 +77,15 @@ DelayJitterEstimation::DelayJitterEstimation () void DelayJitterEstimation::PrepareTx (Ptr packet) { - TimestampTag tag; + DelayJitterEstimationTimestampTag tag; packet->AddTag (tag); } void DelayJitterEstimation::RecordRx (Ptr packet) { - TimestampTag tag; + DelayJitterEstimationTimestampTag tag; bool found; - found = packet->PeekTag (tag); + found = packet->FindFirstMatchingTag (tag); if (!found) { return; diff --git a/src/contrib/gtk-config-store.cc b/src/contrib/gtk-config-store.cc new file mode 100644 index 000000000..025d47d3e --- /dev/null +++ b/src/contrib/gtk-config-store.cc @@ -0,0 +1,538 @@ +#include "gtk-config-store.h" +#include "attribute-iterator.h" +#include "ns3/config.h" +#include "ns3/string.h" +#include "ns3/pointer.h" +#include "ns3/log.h" +#include +#include + + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("GtkconfigStore"); + +enum { + COL_NODE = 0, + COL_LAST +}; + +struct ModelNode +{ + enum { + // store object + attribute name + NODE_ATTRIBUTE, + // store object + attribute name + NODE_POINTER, + // store object + attribute name + NODE_VECTOR, + // store index + value (object) + NODE_VECTOR_ITEM, + // store object + NODE_OBJECT + } type; + std::string name; + Ptr object; + uint32_t index; +}; + +class ModelCreator : public AttributeIterator +{ +public: + ModelCreator (); + + void Build (GtkTreeStore *treestore); +private: + virtual void DoVisitAttribute (Ptr object, std::string name); + virtual void DoStartVisitObject (Ptr object); + virtual void DoEndVisitObject (void); + virtual void DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr value); + virtual void DoEndVisitPointerAttribute (void); + virtual void DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector); + virtual void DoEndVisitArrayAttribute (void); + virtual void DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item); + virtual void DoEndVisitArrayItem (void); + void Add (ModelNode *node); + void Remove (void); + + GtkTreeStore *m_treestore; + std::vector m_iters; +}; + +ModelCreator::ModelCreator () +{} +void +ModelCreator::Build (GtkTreeStore *treestore) +{ + m_treestore = treestore; + m_iters.push_back (NULL); + Iterate (); + NS_ASSERT (m_iters.size () == 1); +} + + +void +ModelCreator::Add (ModelNode *node) +{ + GtkTreeIter *parent = m_iters.back (); + GtkTreeIter *current = g_new (GtkTreeIter, 1); + gtk_tree_store_append (m_treestore, current, parent); + gtk_tree_store_set (m_treestore, current, + COL_NODE, node, + -1); + m_iters.push_back (current); +} +void +ModelCreator::Remove (void) +{ + GtkTreeIter *iter = m_iters.back (); + g_free (iter); + m_iters.pop_back (); +} + +void +ModelCreator::DoVisitAttribute (Ptr object, std::string name) +{ + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_ATTRIBUTE; + node->object = object; + node->name = name; + Add (node); + Remove (); +} +void +ModelCreator::DoStartVisitObject (Ptr object) +{ + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_OBJECT; + node->object = object; + Add (node); +} +void +ModelCreator::DoEndVisitObject (void) +{ + Remove (); +} +void +ModelCreator::DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr value) +{ + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_POINTER; + node->object = object; + node->name = name; + Add (node); +} +void +ModelCreator::DoEndVisitPointerAttribute (void) +{ + Remove (); +} +void +ModelCreator::DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector) +{ + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_VECTOR; + node->object = object; + node->name = name; + Add (node); +} +void +ModelCreator::DoEndVisitArrayAttribute (void) +{ + Remove (); +} +void +ModelCreator::DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item) +{ + GtkTreeIter *parent = m_iters.back (); + GtkTreeIter *current = g_new (GtkTreeIter, 1); + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_VECTOR_ITEM; + node->object = item; + node->index = index; + gtk_tree_store_append (m_treestore, current, parent); + gtk_tree_store_set (m_treestore, current, + COL_NODE, node, + -1); + m_iters.push_back (current); +} +void +ModelCreator::DoEndVisitArrayItem (void) +{ + GtkTreeIter *iter = m_iters.back (); + g_free (iter); + m_iters.pop_back (); +} + +static void +cell_data_function_col_1 (GtkTreeViewColumn *col, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + ModelNode *node; + gtk_tree_model_get (model, iter, COL_NODE, &node, -1); + if (node->type == ModelNode::NODE_ATTRIBUTE) + { + StringValue str; + node->object->GetAttribute (node->name, str); + g_object_set(renderer, "text", str.Get ().c_str (), NULL); + g_object_set(renderer, "editable", TRUE, NULL); + } + else + { + g_object_set(renderer, "text", "", NULL); + g_object_set(renderer, "editable", FALSE, NULL); + } +} + +static void +cell_data_function_col_0 (GtkTreeViewColumn *col, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + ModelNode *node; + gtk_tree_model_get (model, iter, COL_NODE, &node, -1); + g_object_set (renderer, "editable", FALSE, NULL); + switch (node->type) { + case ModelNode::NODE_OBJECT: + g_object_set(renderer, "text", node->object->GetInstanceTypeId ().GetName ().c_str (), NULL); + break; + case ModelNode::NODE_POINTER: + g_object_set(renderer, "text", node->name.c_str (), NULL); + break; + case ModelNode::NODE_VECTOR: + g_object_set(renderer, "text", node->name.c_str (), NULL); + break; + case ModelNode::NODE_VECTOR_ITEM: { + std::stringstream oss; + oss << node->index; + g_object_set(renderer, "text", oss.str ().c_str (), NULL); + } break; + case ModelNode::NODE_ATTRIBUTE: + g_object_set(renderer, "text", node->name.c_str (), NULL); + break; + } +} + + +static void +cell_edited_callback (GtkCellRendererText *cell, + gchar *path_string, + gchar *new_text, + gpointer user_data) +{ + GtkTreeModel *model = GTK_TREE_MODEL (user_data); + GtkTreeIter iter; + gtk_tree_model_get_iter_from_string (model, &iter, path_string); + ModelNode *node; + gtk_tree_model_get (model, &iter, COL_NODE, &node, -1); + NS_ASSERT (node->type == ModelNode::NODE_ATTRIBUTE); + node->object->SetAttribute (node->name, StringValue (new_text)); +} + +static int +get_col_number_from_tree_view_column (GtkTreeViewColumn *col) +{ + GList *cols; + int num; + g_return_val_if_fail ( col != NULL, -1 ); + g_return_val_if_fail ( col->tree_view != NULL, -1 ); + cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view)); + num = g_list_index(cols, (gpointer) col); + g_list_free(cols); + return num; +} + +static gboolean +cell_tooltip_callback (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_tip, + GtkTooltip *tooltip, + gpointer user_data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreeViewColumn * column; + if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), + &x, &y, keyboard_tip, + &model, NULL, &iter)) + { + return FALSE; + } + if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), + x, y, NULL, &column, NULL, NULL)) + { + return FALSE; + } + int col = get_col_number_from_tree_view_column (column); + + ModelNode *node; + gtk_tree_model_get (model, &iter, COL_NODE, &node, -1); + + switch (node->type) { + case ModelNode::NODE_OBJECT: + if (col == 0) + { + std::string tip = "This object is of type " + node->object->GetInstanceTypeId ().GetName (); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + return TRUE; + } + break; + case ModelNode::NODE_POINTER: + if (col == 0) + { + PointerValue ptr; + node->object->GetAttribute (node->name, ptr); + std::string tip = "This object is of type " + ptr.GetObject ()->GetInstanceTypeId ().GetName (); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + return TRUE; + } + break; + case ModelNode::NODE_VECTOR: + break; + case ModelNode::NODE_VECTOR_ITEM: + if (col == 0) + { + std::string tip = "This object is of type " + node->object->GetInstanceTypeId ().GetName (); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + return TRUE; + } + break; + case ModelNode::NODE_ATTRIBUTE: { + uint32_t attrIndex; + TypeId tid; + for (tid = node->object->GetInstanceTypeId (); tid.HasParent (); tid = tid.GetParent ()) + { + for (uint32_t i = 0; i < tid.GetAttributeN (); ++i) + { + if (tid.GetAttributeName (i) == node->name) + { + attrIndex = i; + goto out; + } + } + } + out: + if (col == 0) + { + std::string tip = tid.GetAttributeHelp (attrIndex); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + } + else + { + Ptr checker = tid.GetAttributeChecker (attrIndex); + std::string tip; + tip = "This attribute is of type " + checker->GetValueTypeName (); + if (checker->HasUnderlyingTypeInformation ()) + { + tip += " " + checker->GetUnderlyingTypeInformation (); + } + gtk_tooltip_set_text (tooltip, tip.c_str ()); + } + return TRUE; + } break; + } + return FALSE; +} + + +static GtkWidget * +create_view (GtkTreeStore *model) +{ + GtkTreeViewColumn *col; + GtkCellRenderer *renderer; + GtkWidget *view; + + view = gtk_tree_view_new(); + g_object_set (view, "has-tooltip", TRUE, NULL); + g_signal_connect (view, "query-tooltip", (GCallback) cell_tooltip_callback, NULL); + + gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH); + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE); + + col = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(col, "Object Attributes"); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start(col, renderer, TRUE); + gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_0, NULL, NULL); + g_object_set(renderer, "editable", FALSE, NULL); + + col = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(col, "Attribute Value"); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); + renderer = gtk_cell_renderer_text_new(); + g_signal_connect(renderer, "edited", (GCallback) cell_edited_callback, model); + gtk_tree_view_column_pack_start(col, renderer, TRUE); + gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_1, NULL, NULL); + + + gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL (model)); + + g_object_unref(model); /* destroy model automatically with view */ + + + return view; +} + +static void +save_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *parent_window = GTK_WIDGET (user_data); + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new ("Save File", + GTK_WINDOW (parent_window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); + + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "config.txt"); + + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + char *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + std::ofstream os; + os.open (filename); + TextFileAttributeIterator file = TextFileAttributeIterator (os); + file.Save (); + os.close (); + g_free (filename); + } + + gtk_widget_destroy (dialog); +} + +static void +load_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *parent_window = GTK_WIDGET (user_data); + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new ("Open File", + GTK_WINDOW (parent_window), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + char *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + std::ifstream is; + is.open (filename, std::ios::in); + std::string path, value; + while (is.good()) + { + is >> path >> value; + Config::Set (path, StringValue (value)); + } + g_free (filename); + } + + gtk_widget_destroy (dialog); +} + +static void +exit_clicked_callback (GtkButton *button, + gpointer user_data) +{ + gtk_main_quit (); +} + +static gboolean +delete_event_callback (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + gtk_main_quit (); + return TRUE; +} + +static gboolean +clean_model_callback (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + ModelNode *node; + gtk_tree_model_get (GTK_TREE_MODEL (model), iter, + COL_NODE, &node, + -1); + delete node; + gtk_tree_store_set (GTK_TREE_STORE (model), iter, + COL_NODE, NULL, + -1); + return FALSE; +} + +GtkConfigStore::GtkConfigStore () +{} + +void +GtkConfigStore::Configure (void) +{ + GtkWidget *window; + GtkWidget *view; + GtkWidget *scroll; + + gtk_init (0, 0); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "ns-3 Object attributes."); + gtk_window_set_default_size (GTK_WINDOW (window), 400, 600); + + g_signal_connect (window, "delete_event", (GCallback)delete_event_callback, NULL); + + + GtkTreeStore *model = gtk_tree_store_new (COL_LAST, G_TYPE_POINTER); + ModelCreator creator; + creator.Build (model); + + view = create_view (model); + scroll = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scroll), view); + + GtkWidget *vbox = gtk_vbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0); + gtk_box_pack_end (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 0); + GtkWidget *hbox = gtk_hbox_new (FALSE, 5); + gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + GtkWidget *save = gtk_button_new_with_label ("Save"); + g_signal_connect (save, "clicked", (GCallback) save_clicked, window); + gtk_box_pack_end (GTK_BOX (hbox), save, FALSE, FALSE, 0); + GtkWidget *load = gtk_button_new_with_label ("Load"); + g_signal_connect (load, "clicked", (GCallback) load_clicked, window); + gtk_box_pack_end (GTK_BOX (hbox), load, FALSE, FALSE, 0); + GtkWidget *exit = gtk_button_new_with_label ("Exit"); + g_signal_connect (exit, "clicked", (GCallback) exit_clicked_callback, NULL); + gtk_box_pack_end (GTK_BOX (hbox), exit, FALSE, FALSE, 0); + + gtk_container_add (GTK_CONTAINER (window), vbox); + + gtk_widget_show_all (window); + + gtk_main (); + + gtk_tree_model_foreach (GTK_TREE_MODEL (model), + clean_model_callback, + NULL); + + gtk_widget_destroy (window); +} + +} // namespace ns3 diff --git a/src/contrib/gtk-config-store.h b/src/contrib/gtk-config-store.h new file mode 100644 index 000000000..c1a16408a --- /dev/null +++ b/src/contrib/gtk-config-store.h @@ -0,0 +1,17 @@ +#ifndef GTK_CONFIG_STORE_H +#define GTK_CONFIG_STORE_H + +namespace ns3 { + +class GtkConfigStore +{ +public: + GtkConfigStore (); + + void Configure (void); +}; + + +} // namespace ns3 + +#endif /* GTK_CONFIG_STORE_H */ diff --git a/src/contrib/wscript b/src/contrib/wscript index 557242867..5ef48db70 100644 --- a/src/contrib/wscript +++ b/src/contrib/wscript @@ -1,11 +1,20 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +def configure(conf): + check = conf.create_pkgconfig_configurator() + check.name = 'gtk+-2.0 >= 2.12' + check.uselib = 'GTK_CONFIG_STORE' + check.mandatory = False + conf.env['ENABLE_GTK_CONFIG_STORE'] = check.run() + + def build(bld): module = bld.create_ns3_module('contrib', ['simulator']) module.source = [ 'event-garbage-collector.cc', 'gnuplot.cc', 'delay-jitter-estimation.cc', + 'attribute-iterator.cc', 'config-store.cc', ] @@ -17,3 +26,8 @@ def build(bld): 'delay-jitter-estimation.h', 'config-store.h', ] + + if bld.env()['ENABLE_GTK_CONFIG_STORE']: + headers.source.append ('gtk-config-store.h') + module.source.append ('gtk-config-store.cc') + module.uselib = 'GTK_CONFIG_STORE' diff --git a/src/core/config.cc b/src/core/config.cc index 23233bf79..db12d72a4 100644 --- a/src/core/config.cc +++ b/src/core/config.cc @@ -765,7 +765,7 @@ ConfigTest::RunTests (void) // this should trigger a notification d1->SetAttribute ("Source", IntegerValue (-3)); NS_TEST_ASSERT_EQUAL (m_traceNotification, -3); - NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source") + NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source"); m_traceNotification = 0; m_tracePath = ""; // this should trigger a notification diff --git a/src/core/object.cc b/src/core/object.cc index ede4e43ba..4a1c98dad 100644 --- a/src/core/object.cc +++ b/src/core/object.cc @@ -375,7 +375,7 @@ ObjectTest::RunTests (void) NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0); - NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0) + NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0); baseA = CreateObject (); baseB = CreateObject (); diff --git a/src/core/test.h b/src/core/test.h index e28196af0..1ee298686 100644 --- a/src/core/test.h +++ b/src/core/test.h @@ -100,6 +100,42 @@ private: }; }; // namespace ns3 +#define NS_TEST_ASSERT_EQUAL_FILELINE(got, expected, file, line) \ + do { \ + if ((got) != (expected)) \ + { \ + Failure () << file << ":" <::Get ()->GetParent (m_tid); + return parent != m_tid; +} +bool TypeId::IsChildOf (TypeId other) const { TypeId tmp = *this; diff --git a/src/core/type-id.h b/src/core/type-id.h index 56ef2de94..713f8cb5a 100644 --- a/src/core/type-id.h +++ b/src/core/type-id.h @@ -109,6 +109,8 @@ public: */ TypeId GetParent (void) const; + bool HasParent (void) const; + /** * \param other a parent TypeId * \returns true if the input TypeId is really a parent diff --git a/src/devices/csma/csma-net-device.h b/src/devices/csma/csma-net-device.h index 107873f7c..ac149bf66 100644 --- a/src/devices/csma/csma-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -420,7 +420,6 @@ private: * fire. * * @see class CallBackTraceSource - * @see class TraceResolver */ TracedCallback > m_rxTrace; TracedCallback > m_dropTrace; diff --git a/src/devices/point-to-point/point-to-point-net-device.h b/src/devices/point-to-point/point-to-point-net-device.h index bcf541ff1..ebfaf8239 100644 --- a/src/devices/point-to-point/point-to-point-net-device.h +++ b/src/devices/point-to-point/point-to-point-net-device.h @@ -267,7 +267,6 @@ private: * fire. * * @see class CallBackTraceSource - * @see class TraceResolver */ TracedCallback > m_rxTrace; /** @@ -275,7 +274,6 @@ private: * fire. * * @see class CallBackTraceSource - * @see class TraceResolver */ TracedCallback > m_dropTrace; diff --git a/src/devices/wifi/mac-low.cc b/src/devices/wifi/mac-low.cc index cfeb812f2..8e563b254 100644 --- a/src/devices/wifi/mac-low.cc +++ b/src/devices/wifi/mac-low.cc @@ -40,14 +40,13 @@ namespace ns3 { class SnrTag : public Tag { public: - SnrTag (); - SnrTag (const SnrTag &o); - ~SnrTag (); - static uint32_t GetUid (void); - void Print (std::ostream &os) const; - uint32_t GetSerializedSize (void) const; - void Serialize (Buffer::Iterator i) const; - uint32_t Deserialize (Buffer::Iterator i); + + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); void Set (double snr); double Get (void) const; @@ -55,40 +54,39 @@ private: double m_snr; }; -SnrTag::SnrTag () - : m_snr (0.0) -{} -SnrTag::SnrTag (const SnrTag &o) - : m_snr (o.m_snr) -{} -SnrTag::~SnrTag () -{} -uint32_t -SnrTag::GetUid (void) +TypeId +SnrTag::GetTypeId (void) { - static uint32_t uid = AllocateUid ("SnrTag.ns3.inria.fr"); - return uid; + static TypeId tid = TypeId ("ns3::SnrTag") + .SetParent () + .AddConstructor () + .AddAttribute ("Snr", "The snr of the last packet received", + DoubleValue (0.0), + MakeDoubleAccessor (&SnrTag::Get), + MakeDoubleChecker ()) + ; + return tid; } -void -SnrTag::Print (std::ostream &os) const +TypeId +SnrTag::GetInstanceTypeId (void) const { - os << "snr="< packet, double rxSnr, WifiMode txMode, WifiPreamb { MY_DEBUG ("receive cts from="<PeekTag (tag); + packet->FindFirstMatchingTag (tag); WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ()); station->ReportRxOk (rxSnr, txMode); station->ReportRtsOk (rxSnr, txMode, tag.Get ()); @@ -495,7 +493,7 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb { MY_DEBUG ("receive ack from="<PeekTag (tag); + packet->FindFirstMatchingTag (tag); WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ()); station->ReportRxOk (rxSnr, txMode); station->ReportDataOk (rxSnr, txMode, tag.Get ()); diff --git a/src/devices/wifi/wifi-mac-header.cc b/src/devices/wifi/wifi-mac-header.cc index cd9f8c7c6..5c93e20a1 100644 --- a/src/devices/wifi/wifi-mac-header.cc +++ b/src/devices/wifi/wifi-mac-header.cc @@ -40,7 +40,9 @@ enum { }; WifiMacHeader::WifiMacHeader () - : m_ctrlMoreData (0) + : m_ctrlMoreData (0), + m_ctrlWep (0), + m_ctrlOrder (1) {} WifiMacHeader::~WifiMacHeader () {} diff --git a/src/devices/wifi/wifi-remote-station-manager.cc b/src/devices/wifi/wifi-remote-station-manager.cc index 5e793b9ee..e69943a4d 100644 --- a/src/devices/wifi/wifi-remote-station-manager.cc +++ b/src/devices/wifi/wifi-remote-station-manager.cc @@ -314,11 +314,11 @@ public: WifiMode GetRtsMode (void) const; WifiMode GetDataMode (void) const; - static uint32_t GetUid (void); - void Print (std::ostream &os) const; - void Serialize (ns3::Buffer::Iterator start) const; - uint32_t Deserialize (ns3::Buffer::Iterator start); - uint32_t GetSerializedSize (void) const; + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); private: WifiMode m_rtsMode; WifiMode m_dataMode; @@ -340,30 +340,46 @@ TxModeTag::GetDataMode (void) const { return m_dataMode; } - -uint32_t -TxModeTag::GetUid (void) +TypeId +TxModeTag::GetTypeId (void) { - static uint32_t uid = Tag::AllocateUid ("ns3.wifi.TxModeTag"); - return uid; + static TypeId tid = TypeId ("ns3::TxModeTag") + .SetParent () + .AddConstructor () + .AddAttribute ("RtsTxMode", + "Tx mode of rts to use later", + EmptyAttributeValue (), + MakeWifiModeAccessor (&TxModeTag::GetRtsMode), + MakeWifiModeChecker ()) + .AddAttribute ("DataTxMode", + "Tx mode of data to use later", + EmptyAttributeValue (), + MakeWifiModeAccessor (&TxModeTag::GetDataMode), + MakeWifiModeChecker ()) + ; + return tid; } -void -TxModeTag::Print (std::ostream &os) const +TypeId +TxModeTag::GetInstanceTypeId (void) const { - os << "rts="< ("X", RandomVariableValue (ConstantVariable (0.0)), @@ -40,16 +38,6 @@ MobilityHelper::MobilityHelper () MobilityHelper::~MobilityHelper () {} void -MobilityHelper::EnableNotifier (void) -{ - m_notifierEnabled = true; -} -void -MobilityHelper::DisableNotifier (void) -{ - m_notifierEnabled = false; -} -void MobilityHelper::SetPositionAllocator (Ptr allocator) { m_position = allocator; @@ -156,15 +144,6 @@ MobilityHelper::Install (NodeContainer c) } Vector position = m_position->GetNext (); model->SetPosition (position); - if (m_notifierEnabled) - { - Ptr notifier = - object->GetObject (); - if (notifier == 0) - { - object->AggregateObject (CreateObject ()); - } - } } } diff --git a/src/helper/mobility-helper.h b/src/helper/mobility-helper.h index e1ac293fd..d37eb36c6 100644 --- a/src/helper/mobility-helper.h +++ b/src/helper/mobility-helper.h @@ -42,20 +42,6 @@ public: MobilityHelper (); ~MobilityHelper (); - /** - * After this method is called, every call to MobilityHelper::Install - * will also attach to the new ns3::MobilityModel an ns3::MobilityModelNotifier - * which can be used to listen to CourseChange events. - */ - void EnableNotifier (void); - /** - * After this method is called, no ns3::MobilityModelNotifier object will - * be associated to any new ns3::MobilityModel created by MobilityHelper::Install. - * This will make it impossible to listen to "CourseChange" events from these - * new ns3::MobilityModel instances. - */ - void DisableNotifier (void); - /** * \param allocator allocate initial node positions * @@ -169,9 +155,6 @@ public: * subclass (the type of which was set with MobilityHelper::SetMobilityModel), * aggregates it to the mode, and sets an initial position based on the current * position allocator (set through MobilityHelper::SetPositionAllocator). - * Optionally, this method will also create and aggregate a - * ns3::MobilityModelNotifier to generate 'CourseChange' events based on the - * boolean flag set by MobilityHelper::EnableNotifierAll and MobilityHelper::DisableNotifier. */ void Install (NodeContainer container); @@ -183,7 +166,6 @@ public: private: std::vector > m_mobilityStack; - bool m_notifierEnabled; ObjectFactory m_mobility; Ptr m_position; }; diff --git a/src/helper/ns2-mobility-helper.cc b/src/helper/ns2-mobility-helper.cc index 736c92581..563287b05 100644 --- a/src/helper/ns2-mobility-helper.cc +++ b/src/helper/ns2-mobility-helper.cc @@ -24,7 +24,6 @@ #include "ns3/node-list.h" #include "ns3/node.h" #include "ns3/static-speed-mobility-model.h" -#include "ns3/mobility-model-notifier.h" #include "ns2-mobility-helper.h" NS_LOG_COMPONENT_DEFINE ("Ns2MobilityHelper"); @@ -36,17 +35,6 @@ Ns2MobilityHelper::Ns2MobilityHelper (std::string filename) : m_filename (filename) {} -void -Ns2MobilityHelper::EnableNotifier (void) -{ - m_notifierEnabled = true; -} -void -Ns2MobilityHelper::DisableNotifier (void) -{ - m_notifierEnabled = false; -} - Ptr @@ -67,12 +55,6 @@ Ns2MobilityHelper::GetMobilityModel (std::string idString, const ObjectStore &st model = CreateObject (); object->AggregateObject (model); } - Ptr notifier = object->GetObject (); - if (notifier == 0) - { - notifier = CreateObject (); - object->AggregateObject (notifier); - } return model; } diff --git a/src/helper/ns2-mobility-helper.h b/src/helper/ns2-mobility-helper.h index b112129a1..809a51125 100644 --- a/src/helper/ns2-mobility-helper.h +++ b/src/helper/ns2-mobility-helper.h @@ -42,9 +42,6 @@ public: */ Ns2MobilityHelper (std::string filename); - void EnableNotifier (void); - void DisableNotifier (void); - /** * Read the ns2 trace file and configure the movement * patterns of all nodes contained in the global ns3::NodeList @@ -77,7 +74,6 @@ private: Ptr GetMobilityModel (std::string idString, const ObjectStore &store) const; double ReadDouble (std::string valueString) const; std::string m_filename; - bool m_notifierEnabled; }; } // namespace ns3 diff --git a/src/helper/wifi-helper.cc b/src/helper/wifi-helper.cc index a2d59d2fb..75ecbdf62 100644 --- a/src/helper/wifi-helper.cc +++ b/src/helper/wifi-helper.cc @@ -156,6 +156,7 @@ WifiHelper::EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid oss.str (""); oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/Tx"; Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapPhyTxEvent, pcap)); + oss.str (""); oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/RxOk"; Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapPhyRxEvent, pcap)); } diff --git a/src/internet-node/arp-l3-protocol.h b/src/internet-node/arp-l3-protocol.h index 889966255..8d8870e56 100644 --- a/src/internet-node/arp-l3-protocol.h +++ b/src/internet-node/arp-l3-protocol.h @@ -31,7 +31,7 @@ class ArpCache; class NetDevice; class Node; class Packet; -class TraceContext; + /** * \brief An implementation of the ARP protocol */ diff --git a/src/internet-node/ascii-trace.cc b/src/internet-node/ascii-trace.cc deleted file mode 100644 index 10c8fbc5f..000000000 --- a/src/internet-node/ascii-trace.cc +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * - * 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 - */ -#include "ascii-trace.h" - -#include "ns3/config.h" -#include "ns3/simulator.h" -#include "ns3/node.h" -#include "ns3/packet.h" -#include "ns3/queue.h" - -namespace ns3 { - -AsciiTrace::AsciiTrace (std::string filename) -{ - m_os.open (filename.c_str ()); -} -AsciiTrace::~AsciiTrace () -{ - m_os.close (); -} -void -AsciiTrace::TraceAllQueues (void) -{ - Packet::EnableMetadata (); - Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Enqueue", - MakeCallback (&AsciiTrace::LogDevQueueEnqueue, this)); - Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Dequeue", - MakeCallback (&AsciiTrace::LogDevQueueDequeue, this)); - Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Drop", - MakeCallback (&AsciiTrace::LogDevQueueDrop, this)); -} -void -AsciiTrace::TraceAllNetDeviceRx (void) -{ - Packet::EnableMetadata (); - Config::Connect ("/NodeList/*/DeviceList/*/Rx", - MakeCallback (&AsciiTrace::LogDevRx, this)); -} - -void -AsciiTrace::LogDevQueueEnqueue (std::string context, - Ptr packet) -{ - m_os << "+ "; - m_os << Simulator::Now ().GetSeconds () << " "; - m_os << context; - m_os << " pkt-uid=" << packet->GetUid () << " "; - packet->Print (m_os); - m_os << std::endl; -} - -void -AsciiTrace::LogDevQueueDequeue (std::string context, - Ptr packet) -{ - m_os << "- "; - m_os << Simulator::Now ().GetSeconds () << " "; - m_os << context; - m_os << " pkt-uid=" << packet->GetUid () << " "; - packet->Print (m_os); - m_os << std::endl; -} - -void -AsciiTrace::LogDevQueueDrop (std::string context, - Ptr packet) -{ - m_os << "d "; - m_os << Simulator::Now ().GetSeconds () << " "; - m_os << context; - m_os << " pkt-uid=" << packet->GetUid () << " "; - packet->Print (m_os); - m_os << std::endl; -} -void -AsciiTrace::LogDevRx (std::string context, - Ptr p) -{ - m_os << "r " << Simulator::Now ().GetSeconds () << " "; - m_os << context; - m_os << " pkt-uid=" << p->GetUid () << " "; - p->Print (m_os); - m_os << std::endl; -} - -}//namespace ns3 diff --git a/src/internet-node/ascii-trace.h b/src/internet-node/ascii-trace.h deleted file mode 100644 index 05c505947..000000000 --- a/src/internet-node/ascii-trace.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * - * 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 - */ -#ifndef ASCII_TRACE_H -#define ASCII_TRACE_H - -#include -#include -#include "ns3/ptr.h" - -namespace ns3 { - -class Packet; -class TraceContext; - -class AsciiTrace -{ -public: - AsciiTrace (std::string filename); - ~AsciiTrace (); - void TraceAllQueues (void); - void TraceAllNetDeviceRx (void); -private: - void LogDevQueueEnqueue (std::string context, Ptr p); - void LogDevQueueDequeue (std::string context, Ptr p); - void LogDevQueueDrop (std::string context, Ptr p); - void LogDevRx (std::string context, Ptr p); - std::ofstream m_os; -}; - -}//namespace ns3 - -#endif /* ASCII_TRACE_H */ diff --git a/src/internet-node/ipv4-interface.h b/src/internet-node/ipv4-interface.h index 04828a3e6..5a1e94df5 100644 --- a/src/internet-node/ipv4-interface.h +++ b/src/internet-node/ipv4-interface.h @@ -31,7 +31,6 @@ namespace ns3 { class NetDevice; class Packet; -class TraceContext; /** * \brief The IPv4 representation of a network interface diff --git a/src/internet-node/ipv4-l4-demux.h b/src/internet-node/ipv4-l4-demux.h index 02b5df900..fa04f8a37 100644 --- a/src/internet-node/ipv4-l4-demux.h +++ b/src/internet-node/ipv4-l4-demux.h @@ -32,7 +32,6 @@ namespace ns3 { class Ipv4L4Protocol; class Node; -class TraceContext; /** * \brief L4 Ipv4 Demux diff --git a/src/internet-node/ipv4-l4-protocol.h b/src/internet-node/ipv4-l4-protocol.h index e8e0b12be..e7f2407ad 100644 --- a/src/internet-node/ipv4-l4-protocol.h +++ b/src/internet-node/ipv4-l4-protocol.h @@ -31,8 +31,6 @@ namespace ns3 { class Packet; class Ipv4Address; -class TraceResolver; -class TraceContext; /** * \brief L4 Protocol base class diff --git a/src/internet-node/pcap-trace.cc b/src/internet-node/pcap-trace.cc deleted file mode 100644 index f5d712df2..000000000 --- a/src/internet-node/pcap-trace.cc +++ /dev/null @@ -1,117 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * - * 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 - */ -#include "pcap-trace.h" - -#include - -#include "ns3/config.h" -#include "ns3/callback.h" -#include "ns3/pcap-writer.h" -#include "ns3/node-list.h" -#include "ns3/node.h" -#include "ns3/packet.h" -#include "ns3/log.h" - -#include "ipv4-l3-protocol.h" - -NS_LOG_COMPONENT_DEFINE ("PcapTrace"); - -namespace ns3 { - - -PcapTrace::PcapTrace (std::string filename) - : m_filename (filename) -{} -PcapTrace::~PcapTrace () -{ - for (std::vector::iterator i = m_traces.begin (); - i != m_traces.end (); i++) - { - delete i->writer; - } -} - -void -PcapTrace::TraceAllIp (void) -{ - Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Tx", - MakeCallback (&PcapTrace::LogTxIp, this)); - Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Rx", - MakeCallback (&PcapTrace::LogRxIp, this)); -} - -PcapWriter * -PcapTrace::GetStream (uint32_t nodeId, uint32_t interfaceId) -{ - for (std::vector::iterator i = m_traces.begin (); - i != m_traces.end (); i++) - { - if (i->nodeId == nodeId && - i->interfaceId == interfaceId) - { - return i->writer; - } - } - PcapTrace::Trace trace; - trace.nodeId = nodeId; - trace.interfaceId = interfaceId; - trace.writer = new PcapWriter (); - std::ostringstream oss; - oss << m_filename << "-" << nodeId << "-" << interfaceId; - std::string filename = oss.str (); - trace.writer->Open (filename); - trace.writer->WriteIpHeader (); - m_traces.push_back (trace); - return trace.writer; -} - -uint32_t -PcapTrace::GetNodeIndex (std::string context) const -{ - std::string::size_type pos; - pos = context.find ("/NodeList/"); - NS_ASSERT (pos == 0); - std::string::size_type afterNodeIndex = context.find ("/", 11); - NS_ASSERT (afterNodeIndex != std::string::npos); - std::string index = context.substr (10, afterNodeIndex - 10); - NS_LOG_DEBUG ("index="<> nodeIndex; - return nodeIndex; -} - -void -PcapTrace::LogTxIp (std::string context, Ptr p, uint32_t interfaceIndex) -{ - PcapWriter *writer = GetStream (GetNodeIndex (context), interfaceIndex); - writer->WritePacket (p); -} - -void -PcapTrace::LogRxIp (std::string context, Ptr p, uint32_t interfaceIndex) -{ - PcapWriter *writer = GetStream (GetNodeIndex (context), interfaceIndex); - writer->WritePacket (p); -} - - -}//namespace ns3 diff --git a/src/internet-node/pcap-trace.h b/src/internet-node/pcap-trace.h deleted file mode 100644 index 3ab644684..000000000 --- a/src/internet-node/pcap-trace.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * - * 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 - */ -#ifndef PCAP_TRACE_H -#define PCAP_TRACE_H - -#include -#include -#include "ns3/ptr.h" - -namespace ns3 { - -class Packet; -class TraceContext; -class PcapWriter; - -class PcapTrace -{ -public: - PcapTrace (std::string filename); - ~PcapTrace (); - - void TraceAllIp (void); -private: - PcapWriter *GetStream (uint32_t nodeId, uint32_t interfaceId); - void LogRxIp (std::string context, Ptr p, uint32_t interfaceIndex); - void LogTxIp (std::string context, Ptr p, uint32_t interfaceIndex); - uint32_t GetNodeIndex (std::string context) const; - std::string m_filename; - struct Trace { - uint32_t nodeId; - uint32_t interfaceId; - PcapWriter *writer; - }; - std::vector m_traces; -}; - -}//namespace ns3 - -#endif /* PCAP_TRACE_H */ diff --git a/src/internet-node/tcp-l4-protocol.h b/src/internet-node/tcp-l4-protocol.h index b08eabeba..4555b004e 100644 --- a/src/internet-node/tcp-l4-protocol.h +++ b/src/internet-node/tcp-l4-protocol.h @@ -37,7 +37,6 @@ namespace ns3 { class Node; -class TraceContext; class Socket; class TcpHeader; /** diff --git a/src/internet-node/udp-l4-protocol.h b/src/internet-node/udp-l4-protocol.h index 34f686ffc..ce6ec7cae 100644 --- a/src/internet-node/udp-l4-protocol.h +++ b/src/internet-node/udp-l4-protocol.h @@ -32,7 +32,6 @@ namespace ns3 { class Node; -class TraceContext; class Socket; /** * \brief Implementation of the UDP protocol diff --git a/src/internet-node/wscript b/src/internet-node/wscript index 20f69c7b2..f9687d25a 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -26,8 +26,6 @@ def build(bld): 'tcp-socket-impl.cc', 'ipv4-end-point-demux.cc', 'ipv4-impl.cc', - 'ascii-trace.cc', - 'pcap-trace.cc', 'udp-socket-factory-impl.cc', 'tcp-socket-factory-impl.cc', 'pending-data.cc', @@ -39,8 +37,6 @@ def build(bld): headers.module = 'internet-node' headers.source = [ 'internet-stack.h', - 'ascii-trace.h', - 'pcap-trace.h', 'ipv4-header.h', 'udp-header.h', 'tcp-header.h', diff --git a/src/mobility/hierarchical-mobility-model.cc b/src/mobility/hierarchical-mobility-model.cc index b1fadc473..7a129f052 100644 --- a/src/mobility/hierarchical-mobility-model.cc +++ b/src/mobility/hierarchical-mobility-model.cc @@ -18,7 +18,6 @@ * Author: Mathieu Lacage */ #include "hierarchical-mobility-model.h" -#include "mobility-model-notifier.h" #include "ns3/pointer.h" namespace ns3 { @@ -33,11 +32,13 @@ HierarchicalMobilityModel::GetTypeId (void) .AddConstructor () .AddAttribute ("Child", "The child mobility model.", PointerValue (), - MakePointerAccessor (&HierarchicalMobilityModel::SetChild), + MakePointerAccessor (&HierarchicalMobilityModel::SetChild, + &HierarchicalMobilityModel::GetChild), MakePointerChecker ()) .AddAttribute ("Parent", "The parent mobility model.", PointerValue (), - MakePointerAccessor (&HierarchicalMobilityModel::SetParent), + MakePointerAccessor (&HierarchicalMobilityModel::SetParent, + &HierarchicalMobilityModel::GetParent), MakePointerChecker ()) ; return tid; @@ -52,28 +53,14 @@ void HierarchicalMobilityModel::SetChild (Ptr model) { m_child = model; - Ptr notifier = - m_child->GetObject (); - if (notifier == 0) - { - notifier = CreateObject (); - m_child->AggregateObject (notifier); - } - notifier->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this)); + m_child->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this)); } void HierarchicalMobilityModel::SetParent (Ptr model) { m_parent = model; - Ptr notifier = - m_parent->GetObject (); - if (notifier == 0) - { - notifier = CreateObject (); - m_parent->AggregateObject (notifier); - } - notifier->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this)); + m_parent->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this)); } diff --git a/src/mobility/mobility-model-notifier.h b/src/mobility/mobility-model-notifier.h deleted file mode 100644 index 6fa5e35a4..000000000 --- a/src/mobility/mobility-model-notifier.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * - * 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 - */ -#ifndef MOBILITY_MODEL_NOTIFIER_H -#define MOBILITY_MODEL_NOTIFIER_H - -#include "ns3/object.h" -#include "ns3/callback.h" -#include "ns3/traced-callback.h" -#include "mobility-model.h" - -namespace ns3 { - -/** - * \brief notify listeners of position changes. - */ -class MobilityModelNotifier : public Object -{ -public: - static TypeId GetTypeId (void); - - /** - * Create a new position notifier - */ - MobilityModelNotifier (); - - /** - * \param position the position which just changed. - */ - void Notify (Ptr position) const; -private: - TracedCallback > m_trace; -}; - -} // namespace ns3 - -#endif /* MOBILITY_MODEL_NOTIFIER_H */ diff --git a/src/mobility/mobility-model.cc b/src/mobility/mobility-model.cc index ddfc3592f..9af62c66a 100644 --- a/src/mobility/mobility-model.cc +++ b/src/mobility/mobility-model.cc @@ -17,10 +17,12 @@ * * Author: Mathieu Lacage */ -#include "mobility-model.h" -#include "mobility-model-notifier.h" + #include +#include "mobility-model.h" +#include "ns3/trace-source-accessor.h" + namespace ns3 { TypeId @@ -39,6 +41,9 @@ MobilityModel::GetTypeId (void) VectorValue (Vector (0.0, 0.0, 0.0)), // ignored initial value. MakeVectorAccessor (&MobilityModel::GetVelocity), MakeVectorChecker ()) + .AddTraceSource ("CourseChange", + "The value of the position and/or velocity vector changed", + MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace)) ; return tid; } @@ -77,11 +82,7 @@ MobilityModel::GetDistanceFrom (Ptr other) const void MobilityModel::NotifyCourseChange (void) const { - Ptr notifier = GetObject (); - if (notifier != 0) - { - notifier->Notify (this); - } + m_courseChangeTrace(this); } } // namespace ns3 diff --git a/src/mobility/mobility-model.h b/src/mobility/mobility-model.h index 28cb67457..1d58baf9e 100644 --- a/src/mobility/mobility-model.h +++ b/src/mobility/mobility-model.h @@ -20,9 +20,11 @@ #ifndef MOBILITY_MODEL_H #define MOBILITY_MODEL_H -#include "ns3/object.h" #include "vector.h" +#include "ns3/object.h" +#include "ns3/traced-callback.h" + namespace ns3 { /** @@ -84,6 +86,13 @@ private: * implement this method. */ virtual Vector DoGetVelocity (void) const = 0; + + /** + * Used to alert subscribers that a change in direction, velocity, + * or position has occurred. + */ + TracedCallback > m_courseChangeTrace; + }; }; // namespace ns3 diff --git a/src/mobility/mobility.h b/src/mobility/mobility.h index 6ec1f2541..cca34b6e6 100644 --- a/src/mobility/mobility.h +++ b/src/mobility/mobility.h @@ -5,8 +5,8 @@ * - a set of mobility models which are used to track and maintain * the "current" cartesian position and speed of an object. * - * - a "course change notifier" which can be used to register listeners - * to the course changes of a mobility model: ns3::MobilityModelNotifier. + * - a "course change notifier" trace which can be used to register + * listeners to the course changes of a mobility model * * The mobility models themselves are: * - ns3::StaticMobilityModel: a model which maintains a constant position diff --git a/src/mobility/wscript b/src/mobility/wscript index bd022f38a..2ce6b1844 100644 --- a/src/mobility/wscript +++ b/src/mobility/wscript @@ -6,7 +6,6 @@ def build(bld): 'vector.cc', 'hierarchical-mobility-model.cc', 'mobility-model.cc', - 'mobility-model-notifier.cc', 'position-allocator.cc', 'rectangle.cc', 'static-mobility-model.cc', @@ -23,7 +22,6 @@ def build(bld): 'vector.h', 'hierarchical-mobility-model.h', 'mobility-model.h', - 'mobility-model-notifier.h', 'position-allocator.h', 'rectangle.h', 'static-mobility-model.h', diff --git a/src/node/net-device.h b/src/node/net-device.h index ef6dc69d8..4f3e93d6c 100644 --- a/src/node/net-device.h +++ b/src/node/net-device.h @@ -32,7 +32,6 @@ namespace ns3 { class Node; -class TraceContext; class Channel; class Packet; diff --git a/src/node/node.h b/src/node/node.h index cac3dd22f..272d0f52c 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -29,7 +29,6 @@ namespace ns3 { -class TraceContext; class NetDevice; class Application; class Packet; diff --git a/src/wscript b/src/wscript index b9ff0c36f..83a257919 100644 --- a/src/wscript +++ b/src/wscript @@ -47,6 +47,7 @@ def set_options(opt): def configure(conf): conf.sub_config('core') conf.sub_config('simulator') + conf.sub_config('contrib') blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant())) conf.env['NS3_MODULE_PATH'] = [blddir] diff --git a/utils/bench-packets.cc b/utils/bench-packets.cc index b2da90dd6..ca5b1484f 100644 --- a/utils/bench-packets.cc +++ b/utils/bench-packets.cc @@ -22,6 +22,7 @@ #include "ns3/packet-metadata.h" #include #include +#include using namespace ns3; @@ -39,6 +40,7 @@ public: virtual void Serialize (Buffer::Iterator start) const; virtual uint32_t Deserialize (Buffer::Iterator start); private: + static std::string GetTypeName (void); bool m_ok; }; @@ -54,13 +56,20 @@ BenchHeader::IsOk (void) const return m_ok; } +template +std::string +BenchHeader::GetTypeName (void) +{ + std::ostringstream oss; + oss << "ns3::BenchHeader<" << N << ">"; + return oss.str (); +} + template TypeId BenchHeader::GetTypeId (void) { - std::ostringstream oss; - oss << "ns3::BenchHeader<"<"; - static TypeId tid = TypeId (oss.str ().c_str ()) + static TypeId tid = TypeId (GetTypeName ().c_str ()) .SetParent
() ; return tid; @@ -105,10 +114,72 @@ BenchHeader::Deserialize (Buffer::Iterator start) return N; } +template +class BenchTag : public Tag +{ +public: + static std::string GetName (void) { + std::ostringstream oss; + oss << "anon::BenchTag<" << N << ">"; + return oss.str (); + } + static TypeId GetTypeId (void) { + static TypeId tid = TypeId (GetName ().c_str ()) + .SetParent () + .AddConstructor () + .HideFromDocumentation () + ; + return tid; + } + virtual TypeId GetInstanceTypeId (void) const { + return GetTypeId (); + } + virtual uint32_t GetSerializedSize (void) const { + return N; + } + virtual void Serialize (TagBuffer buf) const { + for (uint32_t i = 0; i < N; ++i) + { + buf.WriteU8 (N); + } + } + virtual void Deserialize (TagBuffer buf) { + for (uint32_t i = 0; i < N; ++i) + { + buf.ReadU8 (); + } + } + BenchTag () + : Tag () {} +}; static void -benchPtrA (uint32_t n) +benchD (uint32_t n) +{ + BenchHeader<25> ipv4; + BenchHeader<8> udp; + BenchTag<16> tag1; + BenchTag<17> tag2; + + for (uint32_t i = 0; i < n; i++) { + Ptr p = Create (2000); + p->AddTag (tag1); + p->AddHeader (udp); + p->FindFirstMatchingTag (tag1); + p->AddTag (tag2); + p->AddHeader (ipv4); + Ptr o = p->Copy (); + o->RemoveHeader (ipv4); + p->FindFirstMatchingTag (tag2); + o->RemoveHeader (udp); + } +} + + + +static void +benchA (uint32_t n) { BenchHeader<25> ipv4; BenchHeader<8> udp; @@ -124,7 +195,7 @@ benchPtrA (uint32_t n) } static void -benchPtrB (uint32_t n) +benchB (uint32_t n) { BenchHeader<25> ipv4; BenchHeader<8> udp; @@ -137,7 +208,7 @@ benchPtrB (uint32_t n) } static void -ptrC2 (Ptr p) +C2 (Ptr p) { BenchHeader<8> udp; @@ -145,15 +216,15 @@ ptrC2 (Ptr p) } static void -ptrC1 (Ptr p) +C1 (Ptr p) { BenchHeader<25> ipv4; p->RemoveHeader (ipv4); - ptrC2 (p); + C2 (p); } static void -benchPtrC (uint32_t n) +benchC (uint32_t n) { BenchHeader<25> ipv4; BenchHeader<8> udp; @@ -162,28 +233,10 @@ benchPtrC (uint32_t n) Ptr p = Create (2000); p->AddHeader (udp); p->AddHeader (ipv4); - ptrC1 (p); + C1 (p); } } -#if 0 -static void -benchPrint (uint32_t n) -{ - PacketPrinter printer; - BenchHeader<25> ipv4; - BenchHeader<8> udp; - Ptr p = Create (2000); - p->AddHeader (udp); - p->AddHeader (ipv4); - - for (uint32_t i = 0; i < n; i++) - { - p->Print (std::cerr, printer); - } -} -#endif - static void runBench (void (*bench) (uint32_t), uint32_t n, char const *name) @@ -218,15 +271,17 @@ int main (int argc, char *argv[]) } std::cout << "Running bench-packets with n=" << n << std::endl; - Packet::EnableMetadata (); - runBench (&benchPtrA, n, "a"); - runBench (&benchPtrB, n, "b"); - runBench (&benchPtrC, n, "c"); + runBench (&benchA, n, "a"); + runBench (&benchB, n, "b"); + runBench (&benchC, n, "c"); + runBench (&benchD, n, "d"); + + Packet::EnableMetadata (); + runBench (&benchA, n, "meta-a"); + runBench (&benchB, n, "meta-b"); + runBench (&benchC, n, "meta-c"); + runBench (&benchD, n, "meta-d"); - //runBench (&benchPrint, n, "print"); - runBench (&benchPtrA, n, "meta-a"); - runBench (&benchPtrB, n, "meta-b"); - runBench (&benchPtrC, n, "meta-c"); return 0;