A Discrete-Event Network Simulator
API
packet-tag-list.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006 INRIA
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18  */
19 
25 #include "packet-tag-list.h"
26 
27 #include "tag-buffer.h"
28 #include "tag.h"
29 
30 #include "ns3/fatal-error.h"
31 #include "ns3/log.h"
32 
33 #include <cstring>
34 
35 namespace ns3
36 {
37 
38 NS_LOG_COMPONENT_DEFINE("PacketTagList");
39 
40 PacketTagList::TagData*
42 {
43  NS_ASSERT_MSG(dataSize < std::numeric_limits<decltype(TagData::size)>::max(),
44  "Requested TagData size " << dataSize << " exceeds maximum "
45  << std::numeric_limits<decltype(TagData::size)>::max());
46 
47  void* p = std::malloc(sizeof(TagData) + dataSize - 1);
48  // The matching frees are in RemoveAll and RemoveWriter
49 
50  auto tag = new (p) TagData;
51  tag->size = dataSize;
52  return tag;
53 }
54 
55 bool
57 {
58  TypeId tid = tag.GetInstanceTypeId();
59  NS_LOG_FUNCTION(this << tid);
60  NS_LOG_INFO("looking for " << tid);
61 
62  // trivial case when list is empty
63  if (m_next == nullptr)
64  {
65  return false;
66  }
67 
68  bool found = false;
69 
70  TagData** prevNext = &m_next; // previous node's next pointer
71  TagData* cur = m_next; // cursor to current node
72  TagData* it = nullptr; // utility
73 
74  // Search from the head of the list until we find tid or a merge
75  while (cur != nullptr)
76  {
77  if (cur->count > 1)
78  {
79  // found merge
80  NS_LOG_INFO("found initial merge before tid");
81  break;
82  }
83  else if (cur->tid == tid)
84  {
85  NS_LOG_INFO("found tid before initial merge, calling writer");
86  found = (this->*Writer)(tag, true, cur, prevNext);
87  break;
88  }
89  else
90  {
91  // no merge or tid found yet, move on
92  prevNext = &cur->next;
93  cur = cur->next;
94  }
95  } // while !found && !cow
96 
97  // did we find it or run out of tags?
98  if (cur == nullptr || found)
99  {
100  NS_LOG_INFO("returning after header with found: " << found);
101  return found;
102  }
103 
104  // From here on out, we have to copy the list
105  // until we find tid, then link past it
106 
107  // Before we do all that work, let's make sure tid really exists
108  for (it = cur; it != nullptr; it = it->next)
109  {
110  if (it->tid == tid)
111  {
112  break;
113  }
114  }
115  if (it == nullptr)
116  {
117  // got to end of list without finding tid
118  NS_LOG_INFO("tid not found after first merge");
119  return found;
120  }
121 
122  // At this point cur is a merge, but untested for tid
123  NS_ASSERT(cur != nullptr);
124  NS_ASSERT(cur->count > 1);
125 
126  /*
127  Walk the remainder of the list, copying, until we find tid
128  As we put a copy of the cur node onto our list,
129  we move the merge point down the list.
130 
131  Starting position End position
132  T1 is a merge T1.count decremented
133  T2 is a merge
134  T1' is a copy of T1
135 
136  other other
137  \ \
138  Prev -> T1 -> T2 -> ... T1 -> T2 -> ...
139  / / /|
140  pNext cur Prev -> T1' --/ |
141  / |
142  pNext cur
143 
144  When we reach tid, we link past it, decrement count, and we're done.
145  */
146 
147  // Should normally check for null cur pointer,
148  // but since we know tid exists, we'll skip this test
149  while (/* cur && */ cur->tid != tid)
150  {
151  NS_ASSERT(cur != nullptr);
152  NS_ASSERT(cur->count > 1);
153  cur->count--; // unmerge cur
154  TagData* copy = CreateTagData(cur->size);
155  copy->tid = cur->tid;
156  copy->count = 1;
157  copy->size = cur->size;
158  memcpy(copy->data, cur->data, copy->size);
159  copy->next = cur->next; // merge into tail
160  copy->next->count++; // mark new merge
161  *prevNext = copy; // point prior list at copy
162  prevNext = &copy->next; // advance
163  cur = copy->next;
164  }
165  // Sanity check:
166  NS_ASSERT(cur != nullptr); // cur should be non-zero
167  NS_ASSERT(cur->tid == tid); // cur->tid should be tid
168  NS_ASSERT(cur->count > 1); // cur should be a merge
169 
170  // link around tid, removing it from our list
171  found = (this->*Writer)(tag, false, cur, prevNext);
172  return found;
173 }
174 
175 bool
177 {
179 }
180 
181 // COWWriter implementing Remove
182 bool
184  bool preMerge,
186  PacketTagList::TagData** prevNext)
187 {
189 
190  // found tid
191  bool found = true;
192  tag.Deserialize(TagBuffer(cur->data, cur->data + cur->size));
193  *prevNext = cur->next; // link around cur
194 
195  if (preMerge)
196  {
197  // found tid before first merge, so delete cur
198  cur->~TagData();
199  std::free(cur);
200  }
201  else
202  {
203  // cur is always a merge at this point
204  // unmerge cur, since we linked around it already
205  cur->count--;
206  if (cur->next != nullptr)
207  {
208  // there's a next, so make it a merge
209  cur->next->count++;
210  }
211  }
212  return found;
213 }
214 
215 bool
217 {
218  bool found = COWTraverse(tag, &PacketTagList::ReplaceWriter);
219  if (!found)
220  {
221  Add(tag);
222  }
223  return found;
224 }
225 
226 // COWWriter implementing Replace
227 bool
229  bool preMerge,
231  PacketTagList::TagData** prevNext)
232 {
234 
235  // found tid
236  bool found = true;
237  if (preMerge)
238  {
239  // found tid before first merge, so just rewrite
240  tag.Serialize(TagBuffer(cur->data, cur->data + cur->size));
241  }
242  else
243  {
244  // cur is always a merge at this point
245  // need to copy, replace, and link past cur
246  cur->count--; // unmerge cur
247  TagData* copy = CreateTagData(tag.GetSerializedSize());
248  copy->tid = tag.GetInstanceTypeId();
249  copy->count = 1;
250  tag.Serialize(TagBuffer(copy->data, copy->data + copy->size));
251  copy->next = cur->next; // merge into tail
252  if (copy->next != nullptr)
253  {
254  copy->next->count++; // mark new merge
255  }
256  *prevNext = copy; // point prior list at copy
257  }
258  return found;
259 }
260 
261 void
262 PacketTagList::Add(const Tag& tag) const
263 {
264  NS_LOG_FUNCTION(this << tag.GetInstanceTypeId());
265  // ensure this id was not yet added
266  for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
267  {
268  NS_ASSERT_MSG(cur->tid != tag.GetInstanceTypeId(),
269  "Error: cannot add the same kind of tag twice. The tag type is "
270  << tag.GetInstanceTypeId().GetName());
271  }
272  TagData* head = CreateTagData(tag.GetSerializedSize());
273  head->count = 1;
274  head->next = nullptr;
275  head->tid = tag.GetInstanceTypeId();
276  head->next = m_next;
277  tag.Serialize(TagBuffer(head->data, head->data + head->size));
278 
279  const_cast<PacketTagList*>(this)->m_next = head;
280 }
281 
282 bool
284 {
285  NS_LOG_FUNCTION(this << tag.GetInstanceTypeId());
286  TypeId tid = tag.GetInstanceTypeId();
287  for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
288  {
289  if (cur->tid == tid)
290  {
291  /* found tag */
292  tag.Deserialize(TagBuffer(cur->data, cur->data + cur->size));
293  return true;
294  }
295  }
296  /* no tag found */
297  return false;
298 }
299 
302 {
303  return m_next;
304 }
305 
306 uint32_t
308 {
310 
311  uint32_t size = 0;
312 
313  size = 4; // numberOfTags
314 
315  for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
316  {
317  size += 4; // TagData -> size
318 
319  // TypeId hash; ensure size is multiple of 4 bytes
320  uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
321  size += hashSize;
322 
323  // TagData -> data; ensure size is multiple of 4 bytes
324  uint32_t tagWordSize = (cur->size + 3) & (~3);
325  size += tagWordSize;
326  }
327 
328  return size;
329 }
330 
331 uint32_t
332 PacketTagList::Serialize(uint32_t* buffer, uint32_t maxSize) const
333 {
334  NS_LOG_FUNCTION(this << buffer << maxSize);
335 
336  uint32_t* p = buffer;
337  uint32_t size = 0;
338 
339  size += 4;
340 
341  if (size > maxSize)
342  {
343  return 0;
344  }
345 
346  uint32_t* numberOfTags = p;
347  *p++ = 0;
348 
349  for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
350  {
351  size += 4;
352 
353  if (size > maxSize)
354  {
355  return 0;
356  }
357 
358  *p++ = cur->size;
359 
360  NS_LOG_INFO("Serializing tag id " << cur->tid);
361 
362  // ensure size is multiple of 4 bytes for 4 byte boundaries
363  uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
364  size += hashSize;
365 
366  if (size > maxSize)
367  {
368  return 0;
369  }
370 
371  TypeId::hash_t tid = cur->tid.GetHash();
372  memcpy(p, &tid, sizeof(TypeId::hash_t));
373  p += hashSize / 4;
374 
375  // ensure size is multiple of 4 bytes for 4 byte boundaries
376  uint32_t tagWordSize = (cur->size + 3) & (~3);
377  size += tagWordSize;
378 
379  if (size > maxSize)
380  {
381  return 0;
382  }
383 
384  memcpy(p, cur->data, cur->size);
385  p += tagWordSize / 4;
386 
387  (*numberOfTags)++;
388  }
389 
390  // Serialized successfully
391  return 1;
392 }
393 
394 uint32_t
395 PacketTagList::Deserialize(const uint32_t* buffer, uint32_t size)
396 {
397  NS_LOG_FUNCTION(this << buffer << size);
398  const uint32_t* p = buffer;
399  uint32_t sizeCheck = size - 4;
400 
401  NS_ASSERT(sizeCheck >= 4);
402  uint32_t numberOfTags = *p++;
403  sizeCheck -= 4;
404 
405  NS_LOG_INFO("Deserializing number of tags " << numberOfTags);
406 
407  TagData* prevTag = nullptr;
408  for (uint32_t i = 0; i < numberOfTags; ++i)
409  {
410  NS_ASSERT(sizeCheck >= 4);
411  uint32_t tagSize = *p++;
412  sizeCheck -= 4;
413 
414  uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
415  NS_ASSERT(sizeCheck >= hashSize);
417  memcpy(&hash, p, sizeof(TypeId::hash_t));
418  p += hashSize / 4;
419  sizeCheck -= hashSize;
420 
422 
423  NS_LOG_INFO("Deserializing tag of type " << tid);
424 
425  TagData* newTag = CreateTagData(tagSize);
426  newTag->count = 1;
427  newTag->next = nullptr;
428  newTag->tid = tid;
429 
430  NS_ASSERT(sizeCheck >= tagSize);
431  memcpy(newTag->data, p, tagSize);
432 
433  // ensure 4 byte boundary
434  uint32_t tagWordSize = (tagSize + 3) & (~3);
435  p += tagWordSize / 4;
436  sizeCheck -= tagWordSize;
437 
438  // Set link list pointers.
439  if (i == 0)
440  {
441  m_next = newTag;
442  }
443  else
444  {
445  prevTag->next = newTag;
446  }
447 
448  prevTag = newTag;
449  }
450 
451  NS_ASSERT(sizeCheck == 0);
452 
453  // return zero if buffer did not
454  // contain a complete message
455  return (sizeCheck != 0) ? 0 : 1;
456 }
457 
458 } /* namespace ns3 */
#define max(a, b)
Definition: 80211b.c:42
virtual TypeId GetInstanceTypeId() const =0
Get the most derived TypeId for this Object.
List of the packet tags stored in a packet.
bool Remove(Tag &tag)
Remove (the first instance of) tag from the list.
void Add(const Tag &tag) const
Add a tag to the head of this branch.
uint32_t Deserialize(const uint32_t *buffer, uint32_t size)
Deserialize tag list from the provided buffer.
uint32_t Serialize(uint32_t *buffer, uint32_t maxSize) const
Serialize the tag list into a byte buffer.
bool ReplaceWriter(Tag &tag, bool preMerge, TagData *cur, TagData **prevNext)
Copy-on-write implementing Replace.
bool Replace(Tag &tag)
Replace the value of a tag.
bool Peek(Tag &tag) const
Find a tag and return its value.
uint32_t GetSerializedSize() const
Returns number of bytes required for packet serialization.
bool COWTraverse(Tag &tag, PacketTagList::COWWriter Writer)
Traverse the list implementing copy-on-write, using Writer.
bool RemoveWriter(Tag &tag, bool preMerge, TagData *cur, TagData **prevNext)
Copy-on-write implementing Remove.
const PacketTagList::TagData * Head() const
TagData * m_next
Pointer to first TagData on the list.
static TagData * CreateTagData(size_t dataSize)
Allocate and construct a TagData struct, sizing the data area large enough to serialize dataSize byte...
bool(PacketTagList::* COWWriter)(Tag &tag, bool preMerge, TagData *cur, TagData **prevNext)
Typedef of method function pointer for copy-on-write operations.
read and write tag data
Definition: tag-buffer.h:52
tag a set of bytes in a packet
Definition: tag.h:39
virtual uint32_t GetSerializedSize() const =0
virtual void Serialize(TagBuffer i) const =0
virtual void Deserialize(TagBuffer i)=0
a unique identifier for an interface.
Definition: type-id.h:59
static TypeId LookupByHash(hash_t hash)
Get a TypeId by hash.
Definition: type-id.cc:857
uint32_t hash_t
Type of hash values.
Definition: type-id.h:120
std::string GetName() const
Get the name.
Definition: type-id.cc:991
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
std::size_t hash(const BasicJsonType &j)
hash a JSON value
Definition: json.h:4680
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Defines a linked list of Packet tags, including copy-on-write semantics.
Tree node for sharing serialized tags.
TagData * next
Pointer to next in list.
TypeId tid
Type of the tag serialized into data.
uint32_t size
Size of the data buffer.
uint32_t count
Number of incoming links.
uint8_t data[1]
Serialization buffer.