A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
35namespace ns3
36{
37
38NS_LOG_COMPONENT_DEFINE("PacketTagList");
39
40PacketTagList::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 TagData* tag = new (p) TagData;
51 tag->size = dataSize;
52 return tag;
53}
54
55bool
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
175bool
177{
179}
180
181// COWWriter implementing Remove
182bool
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
215bool
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
227bool
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
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
261void
262PacketTagList::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.");
270 }
272 head->count = 1;
273 head->next = nullptr;
274 head->tid = tag.GetInstanceTypeId();
275 head->next = m_next;
276 tag.Serialize(TagBuffer(head->data, head->data + head->size));
277
278 const_cast<PacketTagList*>(this)->m_next = head;
279}
280
281bool
283{
284 NS_LOG_FUNCTION(this << tag.GetInstanceTypeId());
285 TypeId tid = tag.GetInstanceTypeId();
286 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
287 {
288 if (cur->tid == tid)
289 {
290 /* found tag */
291 tag.Deserialize(TagBuffer(cur->data, cur->data + cur->size));
292 return true;
293 }
294 }
295 /* no tag found */
296 return false;
297}
298
301{
302 return m_next;
303}
304
307{
309
310 uint32_t size = 0;
311
312 size = 4; // numberOfTags
313
314 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
315 {
316 size += 4; // TagData -> size
317
318 // TypeId hash; ensure size is multiple of 4 bytes
319 uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
320 size += hashSize;
321
322 // TagData -> data; ensure size is multiple of 4 bytes
323 uint32_t tagWordSize = (cur->size + 3) & (~3);
324 size += tagWordSize;
325 }
326
327 return size;
328}
329
332{
333 NS_LOG_FUNCTION(this << buffer << maxSize);
334
335 uint32_t* p = buffer;
336 uint32_t size = 0;
337
338 uint32_t* numberOfTags = nullptr;
339
340 if (size + 4 <= maxSize)
341 {
342 numberOfTags = p;
343 *p++ = 0;
344 size += 4;
345 }
346 else
347 {
348 return 0;
349 }
350
351 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
352 {
353 if (size + 4 <= maxSize)
354 {
355 *p++ = cur->size;
356 size += 4;
357 }
358 else
359 {
360 return 0;
361 }
362
363 NS_LOG_INFO("Serializing tag id " << cur->tid);
364
365 // ensure size is multiple of 4 bytes for 4 byte boundaries
366 uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
367 if (size + hashSize <= maxSize)
368 {
369 TypeId::hash_t tid = cur->tid.GetHash();
370 memcpy(p, &tid, sizeof(TypeId::hash_t));
371 p += hashSize / 4;
372 size += hashSize;
373 }
374 else
375 {
376 return 0;
377 }
378
379 // ensure size is multiple of 4 bytes for 4 byte boundaries
380 uint32_t tagWordSize = (cur->size + 3) & (~3);
381 if (size + tagWordSize <= maxSize)
382 {
383 memcpy(p, cur->data, cur->size);
384 size += tagWordSize;
385 p += tagWordSize / 4;
386 }
387 else
388 {
389 return 0;
390 }
391
392 (*numberOfTags)++;
393 }
394
395 // Serialized successfully
396 return 1;
397}
398
401{
402 NS_LOG_FUNCTION(this << buffer << size);
403 const uint32_t* p = buffer;
404 uint32_t sizeCheck = size - 4;
405
406 NS_ASSERT(sizeCheck >= 4);
407 uint32_t numberOfTags = *p++;
408 sizeCheck -= 4;
409
410 NS_LOG_INFO("Deserializing number of tags " << numberOfTags);
411
412 TagData* prevTag = nullptr;
413 for (uint32_t i = 0; i < numberOfTags; ++i)
414 {
415 NS_ASSERT(sizeCheck >= 4);
416 uint32_t tagSize = *p++;
417 sizeCheck -= 4;
418
419 uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
420 NS_ASSERT(sizeCheck >= hashSize);
421 TypeId::hash_t hash;
422 memcpy(&hash, p, sizeof(TypeId::hash_t));
423 p += hashSize / 4;
424 sizeCheck -= hashSize;
425
426 TypeId tid = TypeId::LookupByHash(hash);
427
428 NS_LOG_INFO("Deserializing tag of type " << tid);
429
430 TagData* newTag = CreateTagData(tagSize);
431 newTag->count = 1;
432 newTag->next = nullptr;
433 newTag->tid = tid;
434
435 NS_ASSERT(sizeCheck >= tagSize);
436 memcpy(newTag->data, p, tagSize);
437
438 // ensure 4 byte boundary
439 uint32_t tagWordSize = (tagSize + 3) & (~3);
440 p += tagWordSize / 4;
441 sizeCheck -= tagWordSize;
442
443 // Set link list pointers.
444 if (i == 0)
445 {
446 m_next = newTag;
447 }
448 else
449 {
450 prevTag->next = newTag;
451 }
452
453 prevTag = newTag;
454 }
455
456 NS_ASSERT(sizeCheck == 0);
457
458 // return zero if buffer did not
459 // contain a complete message
460 return (sizeCheck != 0) ? 0 : 1;
461}
462
463} /* 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:862
uint32_t hash_t
Type of hash values.
Definition: type-id.h:120
#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
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.