A Discrete-Event Network Simulator
API
byte-tag-list.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008 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 #include "byte-tag-list.h"
20 
21 #include "ns3/log.h"
22 
23 #include <cstring>
24 #include <limits>
25 #include <vector>
26 
27 #define USE_FREE_LIST 1
28 #define FREE_LIST_SIZE 1000
29 #define OFFSET_MAX (std::numeric_limits<int32_t>::max())
30 
31 namespace ns3
32 {
33 
34 NS_LOG_COMPONENT_DEFINE("ByteTagList");
35 
44 {
45  uint32_t size;
46  uint32_t count;
47  uint32_t dirty;
48  uint8_t data[4];
49 };
50 
51 #ifdef USE_FREE_LIST
59 static class ByteTagListDataFreeList : public std::vector<ByteTagListData*>
60 {
61  public:
64 
65 static uint32_t g_maxSize = 0;
66 
68 {
69  NS_LOG_FUNCTION(this);
70  for (auto i = begin(); i != end(); i++)
71  {
72  auto buffer = (uint8_t*)(*i);
73  delete[] buffer;
74  }
75 }
76 #endif /* USE_FREE_LIST */
77 
79  : buf(buf_)
80 {
81  NS_LOG_FUNCTION(this << &buf_);
82 }
83 
84 bool
86 {
87  NS_LOG_FUNCTION(this);
88  return m_current < m_end;
89 }
90 
93 {
94  NS_ASSERT(HasNext());
95  Item item = Item(TagBuffer(m_current + 16, m_end));
96  item.tid.SetUid(m_nextTid);
97  item.size = m_nextSize;
100  m_current += 4 + 4 + 4 + 4 + item.size;
101  item.buf.TrimAtEnd(m_end - m_current);
102  PrepareForNext();
103  return item;
104 }
105 
106 void
108 {
109  NS_LOG_FUNCTION(this);
110  while (m_current < m_end)
111  {
113  m_nextTid = buf.ReadU32();
114  m_nextSize = buf.ReadU32();
115  m_nextStart = buf.ReadU32() + m_adjustment;
116  m_nextEnd = buf.ReadU32() + m_adjustment;
118  {
119  m_current += 4 + 4 + 4 + 4 + m_nextSize;
120  }
121  else
122  {
123  break;
124  }
125  }
126 }
127 
129  uint8_t* end,
130  int32_t offsetStart,
131  int32_t offsetEnd,
132  int32_t adjustment)
133  : m_current(start),
134  m_end(end),
135  m_offsetStart(offsetStart),
136  m_offsetEnd(offsetEnd),
137  m_adjustment(adjustment)
138 {
139  NS_LOG_FUNCTION(this << &start << &end << offsetStart << offsetEnd << adjustment);
140  PrepareForNext();
141 }
142 
143 uint32_t
145 {
146  NS_LOG_FUNCTION(this);
147  return m_offsetStart;
148 }
149 
151  : m_minStart(INT32_MAX),
152  m_maxEnd(INT32_MIN),
153  m_adjustment(0),
154  m_used(0),
155  m_data(nullptr)
156 {
157  NS_LOG_FUNCTION(this);
158 }
159 
161  : m_minStart(o.m_minStart),
162  m_maxEnd(o.m_maxEnd),
163  m_adjustment(o.m_adjustment),
164  m_used(o.m_used),
165  m_data(o.m_data)
166 {
167  NS_LOG_FUNCTION(this << &o);
168  if (m_data != nullptr)
169  {
170  m_data->count++;
171  }
172 }
173 
176 {
177  if (this == &o)
178  {
179  return *this;
180  }
181 
184  m_maxEnd = o.m_maxEnd;
186  m_data = o.m_data;
187  m_used = o.m_used;
188  if (m_data != nullptr)
189  {
190  m_data->count++;
191  }
192  return *this;
193 }
194 
196 {
197  NS_LOG_FUNCTION(this);
199  m_data = nullptr;
200  m_used = 0;
201 }
202 
203 TagBuffer
204 ByteTagList::Add(TypeId tid, uint32_t bufferSize, int32_t start, int32_t end)
205 {
206  NS_LOG_FUNCTION(this << tid << bufferSize << start << end);
207  uint32_t spaceNeeded = m_used + bufferSize + 4 + 4 + 4 + 4;
208  NS_ASSERT(m_used <= spaceNeeded);
209  if (m_data == nullptr)
210  {
211  m_data = Allocate(spaceNeeded);
212  m_used = 0;
213  }
214  else if (m_data->size < spaceNeeded || (m_data->count != 1 && m_data->dirty != m_used))
215  {
216  ByteTagListData* newData = Allocate(spaceNeeded);
217  std::memcpy(&newData->data, &m_data->data, m_used);
219  m_data = newData;
220  }
221  TagBuffer tag = TagBuffer(&m_data->data[m_used], &m_data->data[spaceNeeded]);
222  tag.WriteU32(tid.GetUid());
223  tag.WriteU32(bufferSize);
224  tag.WriteU32(start - m_adjustment);
225  tag.WriteU32(end - m_adjustment);
226  if (start - m_adjustment < m_minStart)
227  {
229  }
230  if (end - m_adjustment > m_maxEnd)
231  {
232  m_maxEnd = end - m_adjustment;
233  }
234  m_used = spaceNeeded;
235  m_data->dirty = m_used;
236  return tag;
237 }
238 
239 void
241 {
242  NS_LOG_FUNCTION(this << &o);
244  while (i.HasNext())
245  {
247  TagBuffer buf = Add(item.tid, item.size, item.start, item.end);
248  buf.CopyFrom(item.buf);
249  }
250 }
251 
252 void
254 {
255  NS_LOG_FUNCTION(this);
257  m_minStart = INT32_MAX;
258  m_maxEnd = INT32_MIN;
259  m_adjustment = 0;
260  m_data = nullptr;
261  m_used = 0;
262 }
263 
266 {
267  NS_LOG_FUNCTION(this);
268  // I am not totally sure but I might need to use
269  // INT32_MIN instead of zero below.
270  return Begin(0, OFFSET_MAX);
271 }
272 
274 ByteTagList::Begin(int32_t offsetStart, int32_t offsetEnd) const
275 {
276  NS_LOG_FUNCTION(this << offsetStart << offsetEnd);
277  if (m_data == nullptr)
278  {
279  return Iterator(nullptr, nullptr, offsetStart, offsetEnd, 0);
280  }
281  else
282  {
283  return Iterator(m_data->data, &m_data->data[m_used], offsetStart, offsetEnd, m_adjustment);
284  }
285 }
286 
287 void
288 ByteTagList::AddAtEnd(int32_t appendOffset)
289 {
290  NS_LOG_FUNCTION(this << appendOffset);
291  if (m_maxEnd <= appendOffset - m_adjustment)
292  {
293  return;
294  }
297  while (i.HasNext())
298  {
300 
301  if (item.start >= appendOffset)
302  {
303  continue;
304  }
305  if (item.end > appendOffset)
306  {
307  item.end = appendOffset;
308  }
309  TagBuffer buf = list.Add(item.tid, item.size, item.start, item.end);
310  buf.CopyFrom(item.buf);
311  if (item.end > m_maxEnd)
312  {
313  m_maxEnd = item.end;
314  }
315  }
316  *this = list;
317 }
318 
319 void
320 ByteTagList::AddAtStart(int32_t prependOffset)
321 {
322  NS_LOG_FUNCTION(this << prependOffset);
323  if (m_minStart >= prependOffset - m_adjustment)
324  {
325  return;
326  }
327  m_minStart = INT32_MAX;
330  while (i.HasNext())
331  {
333 
334  if (item.end <= prependOffset)
335  {
336  continue;
337  }
338  if (item.start < prependOffset)
339  {
340  item.start = prependOffset;
341  }
342  TagBuffer buf = list.Add(item.tid, item.size, item.start, item.end);
343  buf.CopyFrom(item.buf);
344  if (item.start < m_minStart)
345  {
346  m_minStart = item.start;
347  }
348  }
349  *this = list;
350 }
351 
352 #ifdef USE_FREE_LIST
353 
355 ByteTagList::Allocate(uint32_t size)
356 {
357  NS_LOG_FUNCTION(this << size);
358  while (!g_freeList.empty())
359  {
360  ByteTagListData* data = g_freeList.back();
361  g_freeList.pop_back();
362  NS_ASSERT(data != nullptr);
363  if (data->size >= size)
364  {
365  data->count = 1;
366  data->dirty = 0;
367  return data;
368  }
369  auto buffer = (uint8_t*)data;
370  delete[] buffer;
371  }
372  auto buffer = new uint8_t[std::max(size, g_maxSize) + sizeof(ByteTagListData) - 4];
373  auto data = (ByteTagListData*)buffer;
374  data->count = 1;
375  data->size = size;
376  data->dirty = 0;
377  return data;
378 }
379 
380 void
382 {
383  NS_LOG_FUNCTION(this << data);
384  if (data == nullptr)
385  {
386  return;
387  }
388  g_maxSize = std::max(g_maxSize, data->size);
389  data->count--;
390  if (data->count == 0)
391  {
392  if (g_freeList.size() > FREE_LIST_SIZE || data->size < g_maxSize)
393  {
394  auto buffer = (uint8_t*)data;
395  delete[] buffer;
396  }
397  else
398  {
399  g_freeList.push_back(data);
400  }
401  }
402 }
403 
404 #else /* USE_FREE_LIST */
405 
407 ByteTagList::Allocate(uint32_t size)
408 {
409  NS_LOG_FUNCTION(this << size);
410  uint8_t* buffer = new uint8_t[size + sizeof(ByteTagListData) - 4];
412  data->count = 1;
413  data->size = size;
414  data->dirty = 0;
415  return data;
416 }
417 
418 void
419 ByteTagList::Deallocate(ByteTagListData* data)
420 {
421  NS_LOG_FUNCTION(this << data);
422  if (data == 0)
423  {
424  return;
425  }
426  data->count--;
427  if (data->count == 0)
428  {
429  uint8_t* buffer = (uint8_t*)data;
430  delete[] buffer;
431  }
432 }
433 
434 #endif /* USE_FREE_LIST */
435 
436 uint32_t
438 {
440 
441  uint32_t size = 0;
442 
443  // Number of tags in list
444  size += 4; // numberOfTags
445 
447  while (i.HasNext())
448  {
450 
451  // TypeId hash; ensure size is multiple of 4 bytes
452  uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
453  size += hashSize;
454 
455  size += 3 * 4; // size, start, end
456 
457  // tag data; ensure size is multiple of 4 bytes
458  uint32_t tagWordSize = (item.size + 3) & (~3);
459  size += tagWordSize;
460  }
461 
462  return size;
463 }
464 
465 uint32_t
466 ByteTagList::Serialize(uint32_t* buffer, uint32_t maxSize) const
467 {
468  NS_LOG_FUNCTION(this << buffer << maxSize);
469 
470  uint32_t* p = buffer;
471  uint32_t size = 0;
472 
473  size += 4;
474 
475  if (size > maxSize)
476  {
477  return 0;
478  }
479 
480  uint32_t* numberOfTags = p;
481  *p++ = 0;
482 
484  while (i.HasNext())
485  {
487 
488  NS_LOG_INFO("Serializing " << item.tid);
489 
490  // ensure size is multiple of 4 bytes for 4 byte boundaries
491  uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
492  size += hashSize;
493 
494  if (size > maxSize)
495  {
496  return 0;
497  }
498 
499  TypeId::hash_t tid = item.tid.GetHash();
500  memcpy(p, &tid, sizeof(TypeId::hash_t));
501  p += hashSize / 4;
502 
503  size += 4;
504 
505  if (size > maxSize)
506  {
507  return 0;
508  }
509 
510  *p++ = item.size;
511 
512  size += 4;
513 
514  if (size > maxSize)
515  {
516  return 0;
517  }
518 
519  *p++ = item.start;
520 
521  size += 4;
522 
523  if (size > maxSize)
524  {
525  return 0;
526  }
527 
528  *p++ = item.end;
529 
530  // ensure size is multiple of 4 bytes for 4 byte boundaries
531  uint32_t tagWordSize = (item.size + 3) & (~3);
532  size += tagWordSize;
533 
534  if (size > maxSize)
535  {
536  return 0;
537  }
538 
539  item.buf.Read(reinterpret_cast<uint8_t*>(p), item.size);
540  p += tagWordSize / 4;
541 
542  (*numberOfTags)++;
543  }
544 
545  // Serialized successfully
546  return 1;
547 }
548 
549 uint32_t
550 ByteTagList::Deserialize(const uint32_t* buffer, uint32_t size)
551 {
552  NS_LOG_FUNCTION(this << buffer << size);
553  const uint32_t* p = buffer;
554  uint32_t sizeCheck = size - 4;
555 
556  NS_ASSERT(sizeCheck >= 4);
557  uint32_t numberTagData = *p++;
558  sizeCheck -= 4;
559 
560  NS_LOG_INFO("Deserializing number of tags " << numberTagData);
561 
562  for (uint32_t i = 0; i < numberTagData; ++i)
563  {
564  uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
565  NS_ASSERT(sizeCheck >= hashSize);
567  memcpy(&hash, p, sizeof(TypeId::hash_t));
568  p += hashSize / 4;
569  sizeCheck -= hashSize;
570 
572 
573  NS_ASSERT(sizeCheck >= 4);
574  uint32_t bufferSize = *p++;
575  sizeCheck -= 4;
576 
577  NS_ASSERT(sizeCheck >= 4);
578  uint32_t start = *p++;
579  sizeCheck -= 4;
580 
581  NS_ASSERT(sizeCheck >= 4);
582  uint32_t end = *p++;
583  sizeCheck -= 4;
584 
585  NS_ASSERT(sizeCheck >= bufferSize);
586  TagBuffer buf = Add(tid, bufferSize, start, end);
587  buf.Write(reinterpret_cast<const uint8_t*>(p), bufferSize);
588 
589  // ensure 4 byte boundary
590  uint32_t tagSizeBytes = (bufferSize + 3) & (~3);
591  sizeCheck -= tagSizeBytes;
592  p += tagSizeBytes / 4;
593  }
594 
595  NS_ASSERT(sizeCheck == 0);
596 
597  // return zero if buffer did not
598  // contain a complete message
599  return (sizeCheck != 0) ? 0 : 1;
600 }
601 
602 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
#define FREE_LIST_SIZE
#define OFFSET_MAX
An iterator for iterating through a byte tag list.
Definition: byte-tag-list.h:75
uint8_t * m_current
Current tag.
int32_t m_adjustment
Adjustment to byte tag offsets.
int32_t m_offsetEnd
Offset to the end of the tag from the virtual byte buffer.
ByteTagList::Iterator::Item Next()
Returns the next Item from the ByteTagList.
void PrepareForNext()
Prepare the iterator for the next tag.
int32_t m_nextEnd
End of the next tag.
uint32_t GetOffsetStart() const
Returns the offset from the start of the virtual byte buffer to the ByteTagList.
int32_t m_nextStart
Start of the next tag.
int32_t m_offsetStart
Offset to the start of the tag from the virtual byte buffer.
uint32_t m_nextSize
Size of the next tag.
Iterator(uint8_t *start, uint8_t *end, int32_t offsetStart, int32_t offsetEnd, int32_t adjustment)
Constructor.
bool HasNext() const
Used to determine if the iterator is at the end of the byteTagList.
uint32_t m_nextTid
TypeId of the next tag.
uint8_t * m_end
End tag.
Container class for struct ByteTagListData.
keep track of the byte tags stored in a packet.
Definition: byte-tag-list.h:66
uint32_t Deserialize(const uint32_t *buffer, uint32_t size)
Deserialize tag list from the provided buffer.
void AddAtEnd(int32_t appendOffset)
Make sure that all offsets are smaller than appendOffset which represents the location where new byte...
void Deallocate(ByteTagListData *data)
Deallocates a ByteTagListData.
ByteTagList & operator=(const ByteTagList &o)
Assignment operator, deallocates current data and assigns value of passed in ByteTagList.
ByteTagList::Iterator Begin(int32_t offsetStart, int32_t offsetEnd) const
int32_t m_minStart
minimal start offset
uint32_t m_used
the number of used bytes in the buffer
ByteTagListData * Allocate(uint32_t size)
Allocate the memory for the ByteTagListData.
ByteTagList::Iterator BeginAll() const
Returns an iterator pointing to the very first tag in this list.
void RemoveAll()
Removes all of the tags from the ByteTagList.
int32_t m_adjustment
adjustment to byte tag offsets
TagBuffer Add(TypeId tid, uint32_t bufferSize, int32_t start, int32_t end)
uint32_t Serialize(uint32_t *buffer, uint32_t maxSize) const
Serialize the tag list into a byte buffer.
void AddAtStart(int32_t prependOffset)
Make sure that all offsets are bigger than prependOffset which represents the location where new byte...
int32_t m_maxEnd
maximal end offset
ByteTagListData * m_data
the ByteTagListData structure
uint32_t GetSerializedSize() const
Returns number of bytes required for packet serialization.
read and write tag data
Definition: tag-buffer.h:52
TAG_BUFFER_INLINE uint32_t ReadU32()
Definition: tag-buffer.h:217
void TrimAtEnd(uint32_t trim)
Trim some space from the end.
Definition: tag-buffer.cc:199
void Read(uint8_t *buffer, uint32_t size)
Definition: tag-buffer.cc:183
TAG_BUFFER_INLINE void WriteU32(uint32_t v)
Definition: tag-buffer.h:187
void Write(const uint8_t *buffer, uint32_t size)
Definition: tag-buffer.cc:129
void CopyFrom(TagBuffer o)
Copy the nternal structure of another TagBuffer.
Definition: tag-buffer.cc:207
a unique identifier for an interface.
Definition: type-id.h:59
hash_t GetHash() const
Get the hash.
Definition: type-id.cc:999
void SetUid(uint16_t uid)
Set the internal id of this TypeId.
Definition: type-id.cc:1212
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
uint16_t GetUid() const
Get the internal id of this TypeId.
Definition: type-id.cc:1205
#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_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
ns3::ByteTagListDataFreeList g_freeList
Container for struct ByteTagListData.
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.
static uint32_t g_maxSize
maximum data size (used for allocation)
#define list
uint8_t data[writeSize]
An item specifies an individual tag within a byte buffer.
Definition: byte-tag-list.h:84
TypeId tid
type of the tag
Definition: byte-tag-list.h:85
TagBuffer buf
the data for the tag as generated by Tag::Serialize
Definition: byte-tag-list.h:89
uint32_t size
size of tag data
Definition: byte-tag-list.h:86
int32_t end
offset to the end of the tag from the virtual byte buffer
Definition: byte-tag-list.h:88
Item(TagBuffer buf)
Constructs an item with the given TagBuffer.
int32_t start
offset to the start of the tag from the virtual byte buffer
Definition: byte-tag-list.h:87
Internal representation of the byte tags stored in a packet.
uint32_t dirty
number of bytes actually in use
uint32_t size
size of the data
uint32_t count
use counter (for smart deallocation)
uint8_t data[4]
data