PacketTagList
authorMathieu Lacage <mathieu.lacage@sophia.inria.fr>
Fri, 20 Mar 2009 13:38:51 +0100
changeset 4907 7595791c4666
parent 4279 7cb2938928d4
child 4908 cfdbb4a44f29
PacketTagList
src/common/packet-tag-list.cc
src/common/packet-tag-list.h
src/common/packet.cc
src/common/packet.h
src/common/wscript
--- /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 = &copy->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',
         ]