A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
packet-tag-list.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2006 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 
26 #include "packet-tag-list.h"
27 #include "tag-buffer.h"
28 #include "tag.h"
29 #include "ns3/fatal-error.h"
30 #include "ns3/log.h"
31 #include <cstring>
32 
33 NS_LOG_COMPONENT_DEFINE ("PacketTagList")
34  ;
35 
36 namespace ns3 {
37 
38 bool
40 {
41  TypeId tid = tag.GetInstanceTypeId ();
42  NS_LOG_FUNCTION (this << tid);
43  NS_LOG_INFO ("looking for " << tid);
44 
45  // trivial case when list is empty
46  if (m_next == 0)
47  {
48  return false;
49  }
50 
51  bool found = false;
52 
53  struct TagData ** prevNext = &m_next; // previous node's next pointer
54  struct TagData * cur = m_next; // cursor to current node
55  struct TagData * it = 0; // utility
56 
57  // Search from the head of the list until we find tid or a merge
58  while (cur != 0)
59  {
60  if (cur->count > 1)
61  {
62  // found merge
63  NS_LOG_INFO ("found initial merge before tid");
64  break;
65  }
66  else if (cur->tid == tid)
67  {
68  NS_LOG_INFO ("found tid before initial merge, calling writer");
69  found = (this->*Writer)(tag, true, cur, prevNext);
70  break;
71  }
72  else
73  {
74  // no merge or tid found yet, move on
75  prevNext = &cur->next;
76  cur = cur->next;
77  }
78  } // while !found && !cow
79 
80  // did we find it or run out of tags?
81  if (cur == 0 || found)
82  {
83  NS_LOG_INFO ("returning after header with found: " << found);
84  return found;
85  }
86 
87  // From here on out, we have to copy the list
88  // until we find tid, then link past it
89 
90  // Before we do all that work, let's make sure tid really exists
91  for (it = cur; it != 0; it = it->next)
92  {
93  if (it->tid == tid)
94  {
95  break;
96  }
97  }
98  if (it == 0)
99  {
100  // got to end of list without finding tid
101  NS_LOG_INFO ("tid not found after first merge");
102  return found;
103  }
104 
105  // At this point cur is a merge, but untested for tid
106  NS_ASSERT (cur != 0);
107  NS_ASSERT (cur->count > 1);
108 
109  /*
110  Walk the remainder of the list, copying, until we find tid
111  As we put a copy of the cur node onto our list,
112  we move the merge point down the list.
113 
114  Starting position End position
115  T1 is a merge T1.count decremented
116  T2 is a merge
117  T1' is a copy of T1
118 
119  other other
120  \ \
121  Prev -> T1 -> T2 -> ... T1 -> T2 -> ...
122  / / /|
123  pNext cur Prev -> T1' --/ |
124  / |
125  pNext cur
126 
127  When we reach tid, we link past it, decrement count, and we're done.
128  */
129 
130  // Should normally check for null cur pointer,
131  // but since we know tid exists, we'll skip this test
132  while ( /* cur && */ cur->tid != tid)
133  {
134  NS_ASSERT (cur != 0);
135  NS_ASSERT (cur->count > 1);
136  cur->count--; // unmerge cur
137  struct TagData * copy = new struct TagData ();
138  copy->tid = cur->tid;
139  copy->count = 1;
140  memcpy (copy->data, cur->data, TagData::MAX_SIZE);
141  copy->next = cur->next; // merge into tail
142  copy->next->count++; // mark new merge
143  *prevNext = copy; // point prior list at copy
144  prevNext = &copy->next; // advance
145  cur = copy->next;
146  }
147  // Sanity check:
148  NS_ASSERT (cur != 0); // cur should be non-zero
149  NS_ASSERT (cur->tid == tid); // cur->tid should be tid
150  NS_ASSERT (cur->count > 1); // cur should be a merge
151 
152  // link around tid, removing it from our list
153  found = (this->*Writer)(tag, false, cur, prevNext);
154  return found;
155 
156 }
157 
158 bool
160 {
162 }
163 
164 // COWWriter implementing Remove
165 bool
166 PacketTagList::RemoveWriter (Tag & tag, bool preMerge,
167  struct PacketTagList::TagData * cur,
168  struct PacketTagList::TagData ** prevNext)
169 {
171 
172  // found tid
173  bool found = true;
174  tag.Deserialize (TagBuffer (cur->data,
175  cur->data + TagData::MAX_SIZE));
176  *prevNext = cur->next; // link around cur
177 
178  if (preMerge)
179  {
180  // found tid before first merge, so delete cur
181  delete cur;
182  }
183  else
184  {
185  // cur is always a merge at this point
186  // unmerge cur, since we linked around it already
187  cur->count--;
188  if (cur->next != 0)
189  {
190  // there's a next, so make it a merge
191  cur->next->count++;
192  }
193  }
194  return found;
195 }
196 
197 bool
199 {
200  bool found = COWTraverse (tag, &PacketTagList::ReplaceWriter);
201  if (!found)
202  {
203  Add (tag);
204  }
205  return found;
206 }
207 
208 // COWWriter implementing Replace
209 bool
210 PacketTagList::ReplaceWriter (Tag & tag, bool preMerge,
211  struct PacketTagList::TagData * cur,
212  struct PacketTagList::TagData ** prevNext)
213 {
215 
216  // found tid
217  bool found = true;
218  if (preMerge)
219  {
220  // found tid before first merge, so just rewrite
221  tag.Serialize (TagBuffer (cur->data,
222  cur->data + tag.GetSerializedSize ()));
223  }
224  else
225  {
226  // cur is always a merge at this point
227  // need to copy, replace, and link past cur
228  cur->count--; // unmerge cur
229  struct TagData * copy = new struct TagData ();
230  copy->tid = tag.GetInstanceTypeId ();
231  copy->count = 1;
232  tag.Serialize (TagBuffer (copy->data,
233  copy->data + tag.GetSerializedSize ()));
234  copy->next = cur->next; // merge into tail
235  if (copy->next != 0)
236  {
237  copy->next->count++; // mark new merge
238  }
239  *prevNext = copy; // point prior list at copy
240  }
241  return found;
242 }
243 
244 void
245 PacketTagList::Add (const Tag &tag) const
246 {
247  NS_LOG_FUNCTION (this << tag.GetInstanceTypeId ());
248  // ensure this id was not yet added
249  for (struct TagData *cur = m_next; cur != 0; cur = cur->next)
250  {
251  NS_ASSERT (cur->tid != tag.GetInstanceTypeId ());
252  }
253  struct TagData * head = new struct TagData ();
254  head->count = 1;
255  head->next = 0;
256  head->tid = tag.GetInstanceTypeId ();
257  head->next = m_next;
259  tag.Serialize (TagBuffer (head->data, head->data + tag.GetSerializedSize ()));
260 
261  const_cast<PacketTagList *> (this)->m_next = head;
262 }
263 
264 bool
266 {
267  NS_LOG_FUNCTION (this << tag.GetInstanceTypeId ());
268  TypeId tid = tag.GetInstanceTypeId ();
269  for (struct TagData *cur = m_next; cur != 0; cur = cur->next)
270  {
271  if (cur->tid == tid)
272  {
273  /* found tag */
274  tag.Deserialize (TagBuffer (cur->data, cur->data + TagData::MAX_SIZE));
275  return true;
276  }
277  }
278  /* no tag found */
279  return false;
280 }
281 
282 const struct PacketTagList::TagData *
284 {
285  return m_next;
286 }
287 
288 } /* namespace ns3 */
289 
uint8_t data[MAX_SIZE]
Serialization buffer.
bool Remove(Tag &tag)
Remove (the first instance of) tag from the list.
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:345
struct TagData * next
Pointer to next in list.
virtual uint32_t GetSerializedSize(void) const =0
const struct PacketTagList::TagData * Head(void) const
List of the packet tags stored in a packet.
#define NS_ASSERT(condition)
Definition: assert.h:64
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:171
#define NS_LOG_INFO(msg)
Definition: log.h:298
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
Definition: log.h:309
bool Peek(Tag &tag) const
Find a tag and return its value.
void Add(Tag const &tag) const
Add a tag to the head of this branch.
bool ReplaceWriter(Tag &tag, bool preMerge, struct TagData *cur, struct TagData **prevNext)
Copy-on-write implementing Replace.
Tree node for sharing serialized tags.
bool Replace(Tag &tag)
Replace the value of a tag.
bool RemoveWriter(Tag &tag, bool preMerge, struct TagData *cur, struct TagData **prevNext)
Copy-on-write implementing Remove.
Defines a linked list of Packet tags, including copy-on-write semantics.
virtual void Serialize(TagBuffer i) const =0
tag a set of bytes in a packet
Definition: tag.h:36
bool COWTraverse(Tag &tag, PacketTagList::COWWriter Writer)
Traverse the list implementing copy-on-write, using Writer.
struct TagData * m_next
Pointer to first TagData on the list.
virtual void Deserialize(TagBuffer i)=0
Size of serialization buffer data.
read and write tag data
Definition: tag-buffer.h:51
virtual TypeId GetInstanceTypeId(void) const =0
TypeId tid
Type of the tag serialized into data.
bool(PacketTagList::* COWWriter)(Tag &tag, bool preMerge, struct TagData *cur, struct TagData **prevNext)
Typedef of method function pointer for copy-on-write operations.
a unique identifier for an interface.
Definition: type-id.h:49
uint32_t count
Number of incoming links.