--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-tag-list.cc Fri Mar 20 13:38:51 2009 +0100
@@ -0,0 +1,185 @@
+/* -*- 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 <mathieu.lacage@sophia.inria.fr>
+ */
+#include "packet-tag-list.h"
+#include "tag-buffer.h"
+#include "tag.h"
+#include "ns3/fatal-error.h"
+#include "ns3/log.h"
+#include <string.h>
+
+NS_LOG_COMPONENT_DEFINE ("PacketTagList");
+
+namespace ns3 {
+
+#ifdef USE_FREE_LIST
+
+struct PacketTagList::TagData *PacketTagList::g_free = 0;
+uint32_t PacketTagList::g_nfree = 0;
+
+struct PacketTagList::TagData *
+PacketTagList::AllocData (void) const
+{
+ struct PacketTagList::TagData *retval;
+ if (g_free != 0)
+ {
+ retval = g_free;
+ g_free = g_free->m_next;
+ g_nfree--;
+ }
+ else
+ {
+ retval = new struct PacketTagList::TagData ();
+ }
+ return retval;
+}
+
+void
+PacketTagList::FreeData (struct TagData *data) const
+{
+ if (g_nfree > 1000)
+ {
+ delete data;
+ return;
+ }
+ g_nfree++;
+ data->next = g_free;
+ data->tid = TypeId ();
+ g_free = data;
+}
+#else
+struct PacketTagList::TagData *
+PacketTagList::AllocData (void) const
+{
+ struct PacketTagList::TagData *retval;
+ retval = new struct PacketTagList::TagData ();
+ return retval;
+}
+
+void
+PacketTagList::FreeData (struct TagData *data) const
+{
+ delete data;
+}
+#endif
+
+bool
+PacketTagList::Remove (Tag &tag)
+{
+ TypeId tid = tag.GetInstanceTypeId ();
+ bool found = false;
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->next)
+ {
+ if (cur->tid == tid)
+ {
+ found = true;
+ tag.Deserialize (TagBuffer (cur->data, cur->data+PacketTagList::SIZE));
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ struct TagData *start = 0;
+ struct TagData **prevNext = &start;
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->next)
+ {
+ if (cur->tid == tid)
+ {
+ /**
+ * 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->tid = cur->tid;
+ copy->count = 1;
+ copy->next = 0;
+ memcpy (copy->data, cur->data, PacketTagList::SIZE);
+ *prevNext = copy;
+ prevNext = ©->next;
+ }
+ *prevNext = 0;
+ RemoveAll ();
+ m_next = start;
+ return true;
+}
+
+void
+PacketTagList::Print (std::ostream &os, std::string separator) const
+{
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->next)
+ {
+ NS_ASSERT (cur->tid.HasConstructor ());
+ Callback<ObjectBase *> constructor = cur->tid.GetConstructor ();
+ NS_ASSERT (!constructor.IsNull ());
+ ObjectBase *instance = constructor ();
+ Tag *tag = dynamic_cast<Tag *> (instance);
+ NS_ASSERT (tag != 0);
+ tag->Deserialize (TagBuffer (cur->data, cur->data+PacketTagList::SIZE));
+ tag->Print (os);
+ delete tag;
+ if (cur->next != 0)
+ {
+ os << separator;
+ }
+ }
+}
+
+void
+PacketTagList::Add (const Tag &tag) const
+{
+ // ensure this id was not yet added
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->next)
+ {
+ NS_ASSERT (cur->tid != tag.GetInstanceTypeId ());
+ }
+ struct TagData *head = AllocData ();
+ head->count = 1;
+ head->next = 0;
+ head->tid = tag.GetInstanceTypeId ();
+ head->next = m_next;
+ NS_ASSERT (tag.GetSerializedSize () < PacketTagList::SIZE);
+ tag.Serialize (TagBuffer (head->data, head->data+tag.GetSerializedSize ()));
+
+ const_cast<PacketTagList *> (this)->m_next = head;
+}
+
+bool
+PacketTagList::Peek (Tag &tag) const
+{
+ TypeId tid = tag.GetInstanceTypeId ();
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->next)
+ {
+ if (cur->tid == tid)
+ {
+ /* found tag */
+ tag.Deserialize (TagBuffer (cur->data, cur->data+PacketTagList::SIZE));
+ return true;
+ }
+ }
+ /* no tag found */
+ return false;
+}
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-tag-list.h Fri Mar 20 13:38:51 2009 +0100
@@ -0,0 +1,142 @@
+/* -*- 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 <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TAGS_H
+#define TAGS_H
+
+#include <stdint.h>
+#include <ostream>
+#include "ns3/type-id.h"
+
+namespace ns3 {
+
+class Tag;
+
+/**
+ * \ingroup constants
+ * \brief Tag maximum size
+ * The maximum size (in bytes) of a Tag is stored
+ * in this constant.
+ */
+#define TAGS_MAX_SIZE 16
+
+class PacketTagList {
+public:
+ inline PacketTagList ();
+ inline PacketTagList (PacketTagList const &o);
+ inline PacketTagList &operator = (PacketTagList const &o);
+ inline ~PacketTagList ();
+
+ void Add (Tag const&tag) const;
+ bool Remove (Tag &tag);
+ bool Peek (Tag &tag) const;
+ inline void RemoveAll (void);
+
+ void Print (std::ostream &os, std::string separator) const;
+
+
+ enum {
+ SIZE = TAGS_MAX_SIZE
+ };
+private:
+ struct TagData {
+ uint8_t data[PacketTagList::SIZE];
+ struct TagData *next;
+ TypeId tid;
+ uint32_t count;
+ };
+
+ bool Remove (TypeId tid);
+ struct PacketTagList::TagData *AllocData (void) const;
+ void FreeData (struct TagData *data) const;
+
+ static struct PacketTagList::TagData *g_free;
+ static uint32_t g_nfree;
+
+ struct TagData *m_next;
+};
+
+} // namespace ns3
+
+
+
+namespace ns3 {
+
+PacketTagList::PacketTagList ()
+ : m_next ()
+{}
+
+PacketTagList::PacketTagList (PacketTagList const &o)
+ : m_next (o.m_next)
+{
+ if (m_next != 0)
+ {
+ m_next->count++;
+ }
+}
+
+PacketTagList &
+PacketTagList::operator = (PacketTagList const &o)
+{
+ // self assignment
+ if (m_next == o.m_next)
+ {
+ return *this;
+ }
+ RemoveAll ();
+ m_next = o.m_next;
+ if (m_next != 0)
+ {
+ m_next->count++;
+ }
+ return *this;
+}
+
+PacketTagList::~PacketTagList ()
+{
+ RemoveAll ();
+}
+
+void
+PacketTagList::RemoveAll (void)
+{
+ struct TagData *prev = 0;
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->next)
+ {
+ cur->count--;
+ if (cur->count > 0)
+ {
+ break;
+ }
+ if (prev != 0)
+ {
+ FreeData (prev);
+ }
+ prev = cur;
+ }
+ if (prev != 0)
+ {
+ FreeData (prev);
+ }
+ m_next = 0;
+}
+
+} // namespace ns3
+
+#endif /* TAGS_H */
--- a/src/common/packet.cc Thu Mar 19 11:33:19 2009 -0700
+++ b/src/common/packet.cc Fri Mar 20 13:38:51 2009 +0100
@@ -103,6 +103,7 @@
Packet::Packet ()
: m_buffer (),
m_tagList (),
+ m_packetTagList (),
m_metadata (m_globalUid, 0),
m_refCount (1)
{
@@ -112,6 +113,7 @@
Packet::Packet (const Packet &o)
: m_buffer (o.m_buffer),
m_tagList (o.m_tagList),
+ m_packetTagList (o.m_packetTagList),
m_metadata (o.m_metadata),
m_refCount (1)
{}
@@ -125,6 +127,7 @@
}
m_buffer = o.m_buffer;
m_tagList = o.m_tagList;
+ m_packetTagList = o.m_packetTagList;
m_metadata = o.m_metadata;
return *this;
}
@@ -132,6 +135,7 @@
Packet::Packet (uint32_t size)
: m_buffer (size),
m_tagList (),
+ m_packetTagList (),
m_metadata (m_globalUid, size),
m_refCount (1)
{
@@ -140,6 +144,7 @@
Packet::Packet (uint8_t const*buffer, uint32_t size)
: m_buffer (),
m_tagList (),
+ m_packetTagList (),
m_metadata (m_globalUid, size),
m_refCount (1)
{
@@ -149,9 +154,11 @@
i.Write (buffer, size);
}
-Packet::Packet (const Buffer &buffer, const TagList &tagList, const PacketMetadata &metadata)
+Packet::Packet (const Buffer &buffer, const TagList &tagList,
+ const PacketTagList &packetTagList, const PacketMetadata &metadata)
: m_buffer (buffer),
m_tagList (tagList),
+ m_packetTagList (packetTagList),
m_metadata (metadata),
m_refCount (1)
{}
@@ -166,7 +173,7 @@
PacketMetadata metadata = m_metadata.CreateFragment (start, end);
// again, call the constructor directly rather than
// through Create because it is private.
- return Ptr<Packet> (new Packet (buffer, m_tagList, metadata), false);
+ return Ptr<Packet> (new Packet (buffer, m_tagList, m_packetTagList, metadata), false);
}
uint32_t
@@ -576,6 +583,36 @@
return false;
}
+void
+Packet::AddPacketTag (const Tag &tag) const
+{
+ m_packetTagList.Add (tag);
+}
+bool
+Packet::RemovePacketTag (Tag &tag)
+{
+ bool found = m_packetTagList.Remove (tag);
+ return found;
+}
+bool
+Packet::PeekPacketTag (Tag &tag) const
+{
+ bool found = m_packetTagList.Peek (tag);
+ return found;
+}
+void
+Packet::RemoveAllPacketTags (void)
+{
+ m_packetTagList.RemoveAll ();
+}
+
+void
+Packet::PrintPacketTags (std::ostream &os) const
+{
+ m_packetTagList.Print (os, " ");
+}
+
+
std::ostream& operator<< (std::ostream& os, const Packet &packet)
{
packet.Print (os);
@@ -585,8 +622,6 @@
} // namespace ns3
-
-
#ifdef RUN_SELF_TESTS
#include "ns3/test.h"
@@ -773,14 +808,14 @@
namespace ns3 {
-class PacketTest: public Test
+static class PacketTest: public Test
{
public:
PacketTest ();
virtual bool RunTests (void);
private:
bool DoCheck (Ptr<const Packet> p, const char *file, int line, uint32_t n, ...);
-};
+} g_packetTest;
PacketTest::PacketTest ()
@@ -957,14 +992,41 @@
tmp->AddAtEnd (a);
CHECK (tmp, 1, E (10, 0, 10));
}
-
+
+ {
+ Packet p;
+ ATestTag<10> a;
+ p.AddPacketTag (a);
+ NS_TEST_ASSERT (p.PeekPacketTag (a));
+ ATestTag<11> b;
+ p.AddPacketTag (b);
+ NS_TEST_ASSERT (p.PeekPacketTag (b));
+ NS_TEST_ASSERT (p.PeekPacketTag (a));
+ Packet copy = p;
+ NS_TEST_ASSERT (copy.PeekPacketTag (b));
+ NS_TEST_ASSERT (copy.PeekPacketTag (a));
+ ATestTag<12> c;
+ NS_TEST_ASSERT (!copy.PeekPacketTag (c));
+ copy.AddPacketTag (c);
+ NS_TEST_ASSERT (copy.PeekPacketTag (c));
+ NS_TEST_ASSERT (copy.PeekPacketTag (b));
+ NS_TEST_ASSERT (copy.PeekPacketTag (a));
+ NS_TEST_ASSERT (!p.PeekPacketTag (c));
+ copy.RemovePacketTag (b);
+ NS_TEST_ASSERT (!copy.PeekPacketTag (b));
+ NS_TEST_ASSERT (p.PeekPacketTag (b));
+ p.RemovePacketTag (a);
+ NS_TEST_ASSERT (!p.PeekPacketTag (a));
+ NS_TEST_ASSERT (copy.PeekPacketTag (a));
+ NS_TEST_ASSERT (!p.PeekPacketTag (c));
+ NS_TEST_ASSERT (copy.PeekPacketTag (c));
+ p.RemoveAllPacketTags ();
+ NS_TEST_ASSERT (!p.PeekPacketTag (b));
+ }
return result;
}
-
-static PacketTest g_packetTest;
-
-}; // namespace ns3
+} // namespace ns3
#endif /* RUN_SELF_TESTS */
--- a/src/common/packet.h Thu Mar 19 11:33:19 2009 -0700
+++ b/src/common/packet.h Fri Mar 20 13:38:51 2009 +0100
@@ -27,6 +27,7 @@
#include "packet-metadata.h"
#include "tag.h"
#include "tag-list.h"
+#include "packet-tag-list.h"
#include "ns3/callback.h"
#include "ns3/assert.h"
#include "ns3/ptr.h"
@@ -409,10 +410,49 @@
*/
void RemoveAllTags (void);
+ /**
+ * \param tag the tag to store in this packet
+ *
+ * Add a tag to this packet. This method calls the
+ * Tag::GetSerializedSize and, then, Tag::Serialize.
+ *
+ * Note that this method is const, that is, it does not
+ * modify the state of this packet, which is fairly
+ * un-intuitive.
+ *
+ * \sa AddTag
+ */
+ void AddPacketTag (const Tag &tag) const;
+ /**
+ * \param tag the tag to remove from this packet
+ * \returns true if the requested tag is found, false
+ * otherwise.
+ *
+ * Remove a tag from this packet. This method calls
+ * Tag::Deserialize if the tag is found.
+ */
+ bool RemovePacketTag (Tag &tag);
+ /**
+ * \param tag the tag to search in this packet
+ * \returns true if the requested tag is found, false
+ * otherwise.
+ *
+ * Search a matching tag and call Tag::Deserialize if it is found.
+ */
+ bool PeekPacketTag (Tag &tag) const;
+ /**
+ * Remove all packet tags.
+ */
+ void RemoveAllPacketTags (void);
+
+ void PrintPacketTags (std::ostream &os) const;
+
private:
- Packet (const Buffer &buffer, const TagList &tagList, const PacketMetadata &metadata);
+ Packet (const Buffer &buffer, const TagList &tagList,
+ const PacketTagList &packetTagList, const PacketMetadata &metadata);
Buffer m_buffer;
TagList m_tagList;
+ PacketTagList m_packetTagList;
PacketMetadata m_metadata;
mutable uint32_t m_refCount;
static uint32_t m_globalUid;
@@ -437,11 +477,14 @@
* - ns3::Packet::AddHeader
* - ns3::Packet::AddTrailer
* - both versions of ns3::Packet::AddAtEnd
+ * - ns3::Packet::RemovePacketTag
*
* Non-dirty operations:
* - ns3::Packet::AddTag
* - ns3::Packet::RemoveAllTags
* - ns3::Packet::PeekTag
+ * - ns3::Packet::RemoveAllPacketTags
+ * - ns3::Packet::PeekPacketTag
* - ns3::Packet::RemoveHeader
* - ns3::Packet::RemoveTrailer
* - ns3::Packet::CreateFragment
--- a/src/common/wscript Thu Mar 19 11:33:19 2009 -0700
+++ b/src/common/wscript Fri Mar 20 13:38:51 2009 +0100
@@ -16,6 +16,7 @@
'tag.cc',
'tag-list.cc',
'tag-buffer.cc',
+ 'packet-tag-list.cc',
]
headers = bld.new_task_gen('ns3header')
@@ -33,4 +34,5 @@
'tag.h',
'tag-list.h',
'tag-buffer.h',
+ 'packet-tag-list.h',
]