a new implementation of the PacketHistory API
parent
62aa29999b
commit
47f2db1e23
|
@ -282,6 +282,7 @@ namespace ns3 {
|
|||
|
||||
bool PacketHistory::m_enable = false;
|
||||
uint32_t PacketHistory::m_maxSize = 0;
|
||||
uint16_t PacketHistory::m_chunkUid = 0;
|
||||
PacketHistory::DataFreeList PacketHistory::m_freeList;
|
||||
uint32_t g_nAllocs = 0;
|
||||
uint32_t g_nDeAllocs = 0;
|
||||
|
@ -328,7 +329,321 @@ PacketHistory::Enable (void)
|
|||
m_enable = true;
|
||||
}
|
||||
|
||||
struct PacketHistory::CommandData *
|
||||
PacketHistory::PacketHistory (uint32_t uid, uint32_t size)
|
||||
: m_data (0),
|
||||
m_begin (0),
|
||||
m_end (0),
|
||||
m_used (0),
|
||||
m_packetUid (uid)
|
||||
{
|
||||
if (size > 0)
|
||||
{
|
||||
AddSmall (true, 0, size);
|
||||
}
|
||||
}
|
||||
PacketHistory::PacketHistory (PacketHistory const &o)
|
||||
: m_data (o.m_data),
|
||||
m_begin (o.m_begin),
|
||||
m_end (o.m_end),
|
||||
m_used (o.m_used),
|
||||
m_packetUid (o.m_packetUid)
|
||||
{
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->m_count++;
|
||||
}
|
||||
}
|
||||
PacketHistory &
|
||||
PacketHistory::operator = (PacketHistory const& o)
|
||||
{
|
||||
if (m_data == o.m_data)
|
||||
{
|
||||
// self assignment
|
||||
return *this;
|
||||
}
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketHistory::Recycle (m_data);
|
||||
}
|
||||
}
|
||||
m_data = o.m_data;
|
||||
m_begin = o.m_begin;
|
||||
m_end = o.m_end;
|
||||
m_used = o.m_used;
|
||||
m_packetUid = o.m_packetUid;
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->m_count++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
PacketHistory::~PacketHistory ()
|
||||
{
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketHistory::Recycle (m_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::ReserveCopy (uint32_t size)
|
||||
{
|
||||
struct PacketHistory::Data *newData = PacketHistory::Create (m_used + size);
|
||||
memcpy (newData->m_data, m_data->m_data, m_end);
|
||||
newData->m_dirtyEnd = m_end;
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketHistory::Recycle (m_data);
|
||||
}
|
||||
m_data = newData;
|
||||
}
|
||||
void
|
||||
PacketHistory::Reserve (uint32_t size)
|
||||
{
|
||||
NS_ASSERT (m_data != 0);
|
||||
if (m_data->m_size >= m_used + size &&
|
||||
(m_data->m_count == 1 ||
|
||||
m_data->m_dirtyEnd == m_used))
|
||||
{
|
||||
/* enough room, not dirty. */
|
||||
g_four++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* (enough room and dirty) or (not enough room) */
|
||||
ReserveCopy (size);
|
||||
g_five++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
PacketHistory::GetUleb128Size (uint32_t value) const
|
||||
{
|
||||
uint32_t n = 0;
|
||||
uint32_t tmp = value;
|
||||
do {
|
||||
tmp >>= 7;
|
||||
n++;
|
||||
} while (tmp != 0);
|
||||
return n;
|
||||
}
|
||||
uint32_t
|
||||
PacketHistory::ReadUleb128 (uint8_t **pBuffer) const
|
||||
{
|
||||
uint8_t *buffer = *pBuffer;
|
||||
uint32_t result = 0;
|
||||
uint8_t byte;
|
||||
result = 0;
|
||||
byte = buffer[0];
|
||||
result = (byte & (~0x80));
|
||||
if (!(byte & 0x80))
|
||||
{
|
||||
*pBuffer = buffer + 1;
|
||||
return result;
|
||||
}
|
||||
byte = buffer[1];
|
||||
result = (byte & (~0x80)) << 7;
|
||||
if (!(byte & 0x80))
|
||||
{
|
||||
*pBuffer = buffer + 2;
|
||||
return result;
|
||||
}
|
||||
byte = buffer[2];
|
||||
result = (byte & (~0x80)) << 14;
|
||||
if (!(byte & 0x80))
|
||||
{
|
||||
*pBuffer = buffer + 3;
|
||||
return result;
|
||||
}
|
||||
byte = buffer[3];
|
||||
result = (byte & (~0x80)) << 21;
|
||||
if (!(byte & 0x80))
|
||||
{
|
||||
*pBuffer = buffer + 4;
|
||||
return result;
|
||||
}
|
||||
byte = buffer[4];
|
||||
result = (byte & (~0x80)) << 28;
|
||||
if (!(byte & 0x80))
|
||||
{
|
||||
*pBuffer = buffer + 5;
|
||||
return result;
|
||||
}
|
||||
/* This means that the LEB128 number was not valid.
|
||||
* ie: the last (5th) byte did not have the high-order bit zeroed.
|
||||
*/
|
||||
NS_ASSERT (false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::Append16 (uint16_t value, uint8_t **pBuffer)
|
||||
{
|
||||
uint8_t *buffer = *pBuffer;
|
||||
buffer[0] = value & 0xff;
|
||||
value >>= 8;
|
||||
buffer[1] = value;
|
||||
*pBuffer = buffer + 2;
|
||||
}
|
||||
bool
|
||||
PacketHistory::TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end)
|
||||
{
|
||||
uint8_t *start = *pBuffer;
|
||||
if (value < 0x80 && start < end)
|
||||
{
|
||||
start[0] = value;
|
||||
*pBuffer = start + 1;
|
||||
return true;
|
||||
}
|
||||
if (value < 0x4000 && start + 1 < end)
|
||||
{
|
||||
uint8_t byte = value & (~0x80);
|
||||
start[0] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[1] = value;
|
||||
*pBuffer = start + 2;
|
||||
return true;
|
||||
}
|
||||
if (value < 0x200000 && start + 2 < end)
|
||||
{
|
||||
uint8_t byte = value & (~0x80);
|
||||
start[0] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[1] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[2] = value;
|
||||
*pBuffer = start + 3;
|
||||
return true;
|
||||
}
|
||||
if (start + 3 < end)
|
||||
{
|
||||
uint8_t byte = value & (~0x80);
|
||||
start[0] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[1] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[2] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[3] = value;
|
||||
*pBuffer = start + 4;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
PacketHistory::IsZero16 (uint16_t index)
|
||||
{
|
||||
return m_data->m_data[index] == 0 && m_data->m_data[index+1] == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
PacketHistory::CanAdd (bool atStart)
|
||||
{
|
||||
if (atStart)
|
||||
{
|
||||
return IsZero16 (m_begin+2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return IsZero16 (m_end);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::AddSmall (bool atStart,
|
||||
uint32_t typeUid, uint32_t size)
|
||||
{
|
||||
if (m_data == 0)
|
||||
{
|
||||
m_data = PacketHistory::Create (10);
|
||||
}
|
||||
NS_ASSERT (m_data != 0);
|
||||
uint16_t chunkUid = m_chunkUid;
|
||||
m_chunkUid++;
|
||||
append:
|
||||
uint8_t *start = &m_data->m_data[m_used];
|
||||
uint8_t *end = &m_data->m_data[m_data->m_size];
|
||||
if (end - start >= 7 &&
|
||||
CanAdd (atStart) &&
|
||||
(m_data->m_count == 1 ||
|
||||
m_used == m_data->m_dirtyEnd))
|
||||
{
|
||||
uint8_t *buffer = start;
|
||||
uint16_t next, prev;
|
||||
if (atStart)
|
||||
{
|
||||
next = m_begin;
|
||||
prev = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
next = 0;
|
||||
prev = m_end;
|
||||
}
|
||||
|
||||
Append16 (next, &buffer);
|
||||
Append16 (prev, &buffer);
|
||||
if (TryToAppend (typeUid, &buffer, end) &&
|
||||
TryToAppend (chunkUid, &buffer, end) &&
|
||||
TryToAppend (size, &buffer, end))
|
||||
{
|
||||
uintptr_t written = buffer - start;
|
||||
NS_ASSERT (written <= 0xffff);
|
||||
if (atStart)
|
||||
{
|
||||
m_begin = m_used;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_end = m_used;
|
||||
}
|
||||
m_used += written;
|
||||
m_data->m_dirtyEnd = m_used;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t n = GetUleb128Size (typeUid);
|
||||
n += GetUleb128Size (chunkUid);
|
||||
n += GetUleb128Size (size);
|
||||
n += 2 + 2;
|
||||
Reserve (n);
|
||||
goto append;
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::ReadSmall (struct PacketHistory::SmallItem *item, uint8_t **pBuffer)
|
||||
{
|
||||
uint8_t *buffer = *pBuffer;
|
||||
item->next = buffer[0];
|
||||
item->next |= (buffer[1]) << 8;
|
||||
item->prev = buffer[2];
|
||||
item->prev |= (buffer[3]) << 8;
|
||||
*pBuffer = *pBuffer + 4;
|
||||
item->typeUid = ReadUleb128 (pBuffer);
|
||||
item->size = ReadUleb128 (pBuffer);
|
||||
item->chunkUid = ReadUleb128 (pBuffer);
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::ReadExtra (struct PacketHistory::ExtraItem *item, uint8_t **pBuffer)
|
||||
{
|
||||
item->fragmentStart = ReadUleb128 (pBuffer);
|
||||
item->fragmentEnd = ReadUleb128 (pBuffer);
|
||||
item->packetUid = ReadUleb128 (pBuffer);
|
||||
}
|
||||
|
||||
|
||||
struct PacketHistory::Data *
|
||||
PacketHistory::Create (uint32_t size)
|
||||
{
|
||||
g_nCreate++;
|
||||
|
@ -339,7 +654,7 @@ PacketHistory::Create (uint32_t size)
|
|||
}
|
||||
while (!m_freeList.empty ())
|
||||
{
|
||||
struct PacketHistory::CommandData *data = m_freeList.back ();
|
||||
struct PacketHistory::Data *data = m_freeList.back ();
|
||||
m_freeList.pop_back ();
|
||||
if (data->m_size >= size)
|
||||
{
|
||||
|
@ -355,7 +670,7 @@ PacketHistory::Create (uint32_t size)
|
|||
}
|
||||
|
||||
void
|
||||
PacketHistory::Recycle (struct CommandData *data)
|
||||
PacketHistory::Recycle (struct PacketHistory::Data *data)
|
||||
{
|
||||
g_nRecycle++;
|
||||
NS_DEBUG ("recycle size="<<data->m_size<<", list="<<m_freeList.size ());
|
||||
|
@ -371,338 +686,31 @@ PacketHistory::Recycle (struct CommandData *data)
|
|||
}
|
||||
}
|
||||
|
||||
struct PacketHistory::CommandData *
|
||||
struct PacketHistory::Data *
|
||||
PacketHistory::Allocate (uint32_t n)
|
||||
{
|
||||
g_nAllocs++;
|
||||
uint32_t size = sizeof (struct CommandData);
|
||||
if (n <= 4)
|
||||
uint32_t size = sizeof (struct Data);
|
||||
if (n <= 10)
|
||||
{
|
||||
n = 4;
|
||||
n = 10;
|
||||
}
|
||||
size += (n-4) * (4 + 1);
|
||||
size += n - 10;
|
||||
uint8_t *buf = new uint8_t [size];
|
||||
struct CommandData *data = (struct CommandData *)buf;
|
||||
struct PacketHistory::Data *data = (struct PacketHistory::Data *)buf;
|
||||
data->m_size = n;
|
||||
data->m_count = 1;
|
||||
data->m_dirtyEnd = 0;
|
||||
return data;
|
||||
}
|
||||
void
|
||||
PacketHistory::Deallocate (struct CommandData *data)
|
||||
PacketHistory::Deallocate (struct PacketHistory::Data *data)
|
||||
{
|
||||
g_nDeAllocs++;
|
||||
uint8_t *buf = (uint8_t *)data;
|
||||
delete [] buf;
|
||||
}
|
||||
|
||||
bool
|
||||
PacketHistory::TryToAppendSmallValue (uint32_t value, uint8_t **buffer)
|
||||
{
|
||||
uint8_t *start = *buffer;
|
||||
uint8_t *end = &m_data->m_data[m_data->m_size];
|
||||
if (value < 0x80 && start < end)
|
||||
{
|
||||
start[0] = value;
|
||||
*buffer = start + 1;
|
||||
return true;
|
||||
}
|
||||
if (value < 0x4000 && start + 1 < end)
|
||||
{
|
||||
uint8_t byte = value & (~0x80);
|
||||
start[0] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[1] = value;
|
||||
*buffer = start + 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool
|
||||
PacketHistory::TryToAppendValue (uint32_t value, uint8_t **buffer)
|
||||
{
|
||||
uint8_t *start = *buffer;
|
||||
uint8_t *end = &m_data->m_data[m_data->m_size];
|
||||
if (value < 0x80 && start < end)
|
||||
{
|
||||
start[0] = value;
|
||||
*buffer = start + 1;
|
||||
return true;
|
||||
}
|
||||
if (value < 0x4000 && start + 1 < end)
|
||||
{
|
||||
uint8_t byte = value & (~0x80);
|
||||
start[0] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[1] = value;
|
||||
*buffer = start + 2;
|
||||
return true;
|
||||
}
|
||||
if (value < 0x200000 && start + 2 < end)
|
||||
{
|
||||
uint8_t byte = value & (~0x80);
|
||||
start[0] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[1] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[2] = value;
|
||||
*buffer = start + 3;
|
||||
return true;
|
||||
}
|
||||
if (start + 3 < end)
|
||||
{
|
||||
uint8_t byte = value & (~0x80);
|
||||
start[0] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[1] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[2] = 0x80 | byte;
|
||||
value >>= 7;
|
||||
start[3] = value;
|
||||
*buffer = start + 4;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#if 0
|
||||
// more generic version of the above.
|
||||
do {
|
||||
uint8_t byte = value & (~0x80);
|
||||
value >>= 7;
|
||||
if (value != 0)
|
||||
{
|
||||
/* more bytes to come */
|
||||
byte |= 0x80;
|
||||
}
|
||||
*current = byte;
|
||||
current++;
|
||||
} while (value != 0 && current != end);
|
||||
if (value != 0 && current == end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*buffer = current;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t
|
||||
PacketHistory::GetUleb128Size (uint32_t value) const
|
||||
{
|
||||
uint32_t n = 0;
|
||||
uint32_t tmp = value;
|
||||
do {
|
||||
tmp >>= 7;
|
||||
n++;
|
||||
} while (tmp != 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::AppendValue (uint32_t value)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
uint8_t *buffer = &m_data->m_data[m_end];
|
||||
do {
|
||||
uint8_t byte = value & (~0x80);
|
||||
value >>= 7;
|
||||
if (value != 0)
|
||||
{
|
||||
/* more bytes to come */
|
||||
byte |= 0x80;
|
||||
}
|
||||
n++;
|
||||
*buffer = byte;
|
||||
buffer++;
|
||||
} while (value != 0);
|
||||
m_end += n;
|
||||
if (m_end > m_data->m_dirtyEnd)
|
||||
{
|
||||
m_data->m_dirtyEnd = m_end;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
PacketHistory::ReadValue (uint8_t *buffer, uint32_t *n) const
|
||||
{
|
||||
#ifdef USE_ULEB
|
||||
uint32_t result = 0;
|
||||
uint8_t shift, byte;
|
||||
result = 0;
|
||||
shift = 0;
|
||||
do {
|
||||
byte = *buffer;
|
||||
buffer++;
|
||||
result |= (byte & (~0x80))<<shift;
|
||||
shift += 7;
|
||||
(*n)++;
|
||||
} while (byte & 0x80 &&
|
||||
/* a LEB128 unsigned number is at most 5 bytes long. */
|
||||
shift < (7*5));
|
||||
if (byte & 0x80)
|
||||
{
|
||||
/* This means that the LEB128 number was not valid.
|
||||
* ie: the last (5th) byte did not have the high-order bit zeroed.
|
||||
*/
|
||||
result = 0xffffffff;
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
uint32_t *start = (uint32_t *)buffer;
|
||||
*n = *n + 4;
|
||||
return *start;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PacketHistory::AppendOneCommand (uint32_t type, uint32_t data0, uint32_t data1)
|
||||
{
|
||||
NS_ASSERT (m_data != 0);
|
||||
#ifdef USE_ULEB
|
||||
if (m_data->m_count == 1 ||
|
||||
m_data->m_dirtyEnd == m_end)
|
||||
{
|
||||
uint8_t *start = &m_data->m_data[m_end];
|
||||
uint8_t *current = start;
|
||||
if (TryToAppendSmallValue (type, ¤t) &&
|
||||
TryToAppendSmallValue (data0, ¤t) &&
|
||||
TryToAppendValue (data1, ¤t))
|
||||
{
|
||||
uintptr_t written = current - start;
|
||||
m_end += written;
|
||||
m_data->m_dirtyEnd = m_end;
|
||||
m_n++;
|
||||
g_one++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_two++;
|
||||
uint32_t n = GetUleb128Size (type);
|
||||
n += GetUleb128Size (data0);
|
||||
n += GetUleb128Size (data1);
|
||||
Reserve (n);
|
||||
AppendValue (type);
|
||||
AppendValue (data0);
|
||||
AppendValue (data1);
|
||||
m_n++;
|
||||
|
||||
#else
|
||||
restart:
|
||||
if (m_data->m_count == 1 ||
|
||||
m_data->m_dirtyEnd == m_end)
|
||||
{
|
||||
uint32_t *start = (uint32_t *)&m_data->m_data[m_end];
|
||||
uint32_t *end = (uint32_t *)&m_data->m_data[m_data->m_size];
|
||||
if (start + 2 < end)
|
||||
{
|
||||
start[0] = type;
|
||||
start[1] = data0;
|
||||
start[2] = data1;
|
||||
m_end += 12;
|
||||
m_data->m_dirtyEnd = m_end;
|
||||
m_n++;
|
||||
g_one++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
g_two++;
|
||||
Reserve (12);
|
||||
goto restart;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::AppendOneCommand (uint32_t type, uint32_t data)
|
||||
{
|
||||
NS_ASSERT (m_data != 0);
|
||||
#ifdef USE_ULEB
|
||||
if (m_data->m_count == 1 ||
|
||||
m_data->m_dirtyEnd == m_end)
|
||||
{
|
||||
uint8_t *start = &m_data->m_data[m_end];
|
||||
uint8_t *current = start;
|
||||
if (TryToAppendSmallValue (type, ¤t) &&
|
||||
TryToAppendSmallValue (data, ¤t))
|
||||
{
|
||||
uintptr_t written = current - start;
|
||||
m_end += written;
|
||||
m_data->m_dirtyEnd = m_end;
|
||||
m_n++;
|
||||
g_one++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_two++;
|
||||
uint32_t n = GetUleb128Size (data);
|
||||
n += GetUleb128Size (type);
|
||||
Reserve (n);
|
||||
AppendValue (type);
|
||||
AppendValue (data);
|
||||
m_n++;
|
||||
#else
|
||||
restart:
|
||||
if (m_data->m_count == 1 ||
|
||||
m_data->m_dirtyEnd == m_end)
|
||||
{
|
||||
uint32_t *start = (uint32_t *)&m_data->m_data[m_end];
|
||||
uint32_t *end = (uint32_t *)&m_data->m_data[m_data->m_size];
|
||||
if (start + 1 < end)
|
||||
{
|
||||
start[0] = type;
|
||||
start[1] = data;
|
||||
m_end += 8;
|
||||
m_data->m_dirtyEnd = m_end;
|
||||
m_n++;
|
||||
g_one++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
g_two++;
|
||||
Reserve (8);
|
||||
goto restart;
|
||||
#endif
|
||||
}
|
||||
void
|
||||
PacketHistory::ReserveCopy (uint32_t size)
|
||||
{
|
||||
struct CommandData *newData = PacketHistory::Create (m_end + size);
|
||||
memcpy (newData->m_data, m_data->m_data, m_end);
|
||||
newData->m_dirtyEnd = m_end;
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketHistory::Recycle (m_data);
|
||||
}
|
||||
m_data = newData;
|
||||
}
|
||||
void
|
||||
PacketHistory::Reserve (uint32_t size)
|
||||
{
|
||||
NS_ASSERT (m_data != 0);
|
||||
if (m_data->m_size >= m_end + size &&
|
||||
(m_data->m_count == 1 ||
|
||||
m_data->m_dirtyEnd == m_end))
|
||||
{
|
||||
/* enough room, not dirty. */
|
||||
g_four++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* (enough room and dirty) or (not enough room) */
|
||||
ReserveCopy (size);
|
||||
g_five++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
PacketHistory::ReadForwardValue (uint8_t **pBuffer) const
|
||||
{
|
||||
uint32_t read = 0;
|
||||
uint32_t result = ReadValue (*pBuffer, &read);
|
||||
*pBuffer = *pBuffer + read;
|
||||
return result;
|
||||
}
|
||||
|
||||
PacketHistory
|
||||
PacketHistory::CreateFragment (uint32_t start, uint32_t end) const
|
||||
|
@ -716,141 +724,177 @@ PacketHistory::CreateFragment (uint32_t start, uint32_t end) const
|
|||
void
|
||||
PacketHistory::AddHeader (uint32_t uid, Chunk const & header, uint32_t size)
|
||||
{
|
||||
if (m_enable)
|
||||
if (!m_enable)
|
||||
{
|
||||
AppendOneCommand (PacketHistory::ADD_HEADER, uid, size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
AddSmall (true, uid, size);
|
||||
}
|
||||
void
|
||||
PacketHistory::RemoveHeader (uint32_t uid, Chunk const & header, uint32_t size)
|
||||
{
|
||||
if (m_enable)
|
||||
if (!m_enable)
|
||||
{
|
||||
AppendOneCommand (PacketHistory::REM_HEADER, uid, size);
|
||||
return;
|
||||
}
|
||||
if (m_data == 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("Removing header from empty packet.");
|
||||
}
|
||||
struct PacketHistory::SmallItem item;
|
||||
uint8_t *buffer = &m_data->m_data[m_begin];
|
||||
ReadSmall (&item, &buffer);
|
||||
NS_ASSERT (buffer < &m_data->m_data[m_data->m_size]);
|
||||
if ((item.typeUid & 0xfffffffd) != uid ||
|
||||
item.size != size)
|
||||
{
|
||||
NS_FATAL_ERROR ("Removing unexpected header.");
|
||||
}
|
||||
else if (item.typeUid != uid)
|
||||
{
|
||||
// this is a "big" item
|
||||
struct PacketHistory::ExtraItem extraItem;
|
||||
ReadExtra (&extraItem, &buffer);
|
||||
NS_ASSERT (buffer < &m_data->m_data[m_data->m_size]);
|
||||
if (extraItem.fragmentStart != 0 ||
|
||||
extraItem.fragmentEnd != size)
|
||||
{
|
||||
NS_FATAL_ERROR ("Removing incomplete header.");
|
||||
}
|
||||
}
|
||||
m_begin = item.next;
|
||||
if (m_begin > m_end)
|
||||
{
|
||||
m_used = m_begin;
|
||||
}
|
||||
}
|
||||
void
|
||||
PacketHistory::AddTrailer (uint32_t uid, Chunk const & trailer, uint32_t size)
|
||||
{
|
||||
if (m_enable)
|
||||
if (!m_enable)
|
||||
{
|
||||
AppendOneCommand (PacketHistory::ADD_TRAILER, uid, size);
|
||||
return;
|
||||
}
|
||||
AddSmall (true, uid, size);
|
||||
}
|
||||
void
|
||||
PacketHistory::RemoveTrailer (uint32_t uid, Chunk const & trailer, uint32_t size)
|
||||
{
|
||||
if (m_enable)
|
||||
if (!m_enable)
|
||||
{
|
||||
AppendOneCommand (PacketHistory::REM_TRAILER, uid, size);
|
||||
return;
|
||||
}
|
||||
if (m_data == 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("Removing trailer from empty packet.");
|
||||
}
|
||||
struct PacketHistory::SmallItem item;
|
||||
uint8_t *buffer = &m_data->m_data[m_end];
|
||||
ReadSmall (&item, &buffer);
|
||||
NS_ASSERT (buffer < &m_data->m_data[m_data->m_size]);
|
||||
if ((item.typeUid & 0xfffffffd) != uid ||
|
||||
item.size != size)
|
||||
{
|
||||
NS_FATAL_ERROR ("Removing unexpected trailer.");
|
||||
}
|
||||
else if (item.typeUid != uid)
|
||||
{
|
||||
// this is a "big" item
|
||||
struct PacketHistory::ExtraItem extraItem;
|
||||
ReadExtra (&extraItem, &buffer);
|
||||
NS_ASSERT (buffer < &m_data->m_data[m_data->m_size]);
|
||||
if (extraItem.fragmentStart != 0 ||
|
||||
extraItem.fragmentEnd != size)
|
||||
{
|
||||
NS_FATAL_ERROR ("Removing incomplete trailer.");
|
||||
}
|
||||
}
|
||||
m_end = item.prev;
|
||||
if (m_end > m_begin)
|
||||
{
|
||||
m_used = m_end;
|
||||
}
|
||||
}
|
||||
void
|
||||
PacketHistory::AddAtEnd (PacketHistory const&o)
|
||||
{
|
||||
if (m_enable)
|
||||
if (!m_enable)
|
||||
{
|
||||
uint32_t n = GetUleb128Size (PacketHistory::ADD_AT_END);
|
||||
n += GetUleb128Size (o.m_end);
|
||||
n += GetUleb128Size (o.m_n);
|
||||
n += o.m_end;
|
||||
Reserve (n);
|
||||
AppendOneCommand (PacketHistory::ADD_AT_END, o.m_end, o.m_n);
|
||||
memcpy (&m_data->m_data[m_end], o.m_data->m_data, o.m_end);
|
||||
m_end += o.m_end;
|
||||
if (m_end > m_data->m_dirtyEnd)
|
||||
{
|
||||
m_data->m_dirtyEnd = m_end;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
void
|
||||
PacketHistory::AddPaddingAtEnd (uint32_t end)
|
||||
{
|
||||
if (m_enable)
|
||||
if (!m_enable)
|
||||
{
|
||||
AppendOneCommand (PacketHistory::PADDING_AT_END, end);
|
||||
return;
|
||||
}
|
||||
}
|
||||
void
|
||||
PacketHistory::RemoveAtStart (uint32_t start)
|
||||
{
|
||||
if (m_enable)
|
||||
if (!m_enable)
|
||||
{
|
||||
AppendOneCommand (PacketHistory::REM_AT_START, start);
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
if (m_data == 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("Removing header from empty packet.");
|
||||
}
|
||||
struct PacketHistory::SmallItem item;
|
||||
uint8_t *buffer = &m_data->m_data[m_begin];
|
||||
bool ok = ReadSmall (&item, &buffer);
|
||||
NS_ASSERT (ok);
|
||||
if ((item.typeUid & 0xfffffffd) != uid ||
|
||||
item.size != size)
|
||||
{
|
||||
NS_FATAL_ERROR ("Removing unexpected header.");
|
||||
}
|
||||
else if (item.typeUid != uid)
|
||||
{
|
||||
// this is a "big" item
|
||||
struct PacketHistory::ExtraItem extraItem;
|
||||
ok = ReadExtra (&extraItem, &buffer);
|
||||
NS_ASSERT (ok);
|
||||
if (extraItem.fragmentStart != 0 ||
|
||||
extraItem.fragmentEnd != size)
|
||||
{
|
||||
NS_FATAL_ERROR ("Removing incomplete header.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t leftToRemove = start;
|
||||
while (!m_itemList.empty () && leftToRemove > 0)
|
||||
{
|
||||
struct Item &item = m_itemList.front ();
|
||||
uint32_t itemRealSize = item.m_fragmentEnd - item.m_fragmentStart;
|
||||
if (itemRealSize <= leftToRemove)
|
||||
{
|
||||
m_itemList.pop_front ();
|
||||
leftToRemove -= itemRealSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.m_fragmentStart += leftToRemove;
|
||||
leftToRemove = 0;
|
||||
NS_ASSERT (item.m_size >= item.m_fragmentEnd - item.m_fragmentStart &&
|
||||
item.m_fragmentStart <= item.m_fragmentEnd);
|
||||
}
|
||||
}
|
||||
NS_ASSERT (leftToRemove == 0);
|
||||
#endif
|
||||
}
|
||||
void
|
||||
PacketHistory::RemoveAtEnd (uint32_t end)
|
||||
{
|
||||
if (m_enable)
|
||||
if (!m_enable)
|
||||
{
|
||||
AppendOneCommand (PacketHistory::REM_AT_END, end);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::PrintComplex (std::ostream &os, Buffer buffer, const PacketPrinter &printer) const
|
||||
{
|
||||
// we need to build a linked list of the different fragments
|
||||
// which are stored in this packet.
|
||||
uint8_t *dataBuffer = &m_data->m_data[0];
|
||||
ItemList itemList;
|
||||
BuildItemList (&itemList, &dataBuffer, m_end, m_n);
|
||||
itemList.Print (os, buffer, printer);
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::BuildItemList (ItemList *list, uint8_t **buffer, uint32_t size, uint32_t n) const
|
||||
{
|
||||
// we need to build a linked list of the different fragments
|
||||
// which are stored in this packet.
|
||||
uint8_t *dataBuffer = *buffer;
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
uint32_t type = ReadForwardValue (&dataBuffer);
|
||||
uint32_t data = ReadForwardValue (&dataBuffer);
|
||||
switch (type)
|
||||
{
|
||||
case INIT: {
|
||||
uint32_t uid = ReadForwardValue (&dataBuffer);
|
||||
list->InitPayload (uid, data);
|
||||
} break;
|
||||
case ADD_HEADER: {
|
||||
uint32_t size = ReadForwardValue (&dataBuffer);
|
||||
list->AddHeader (data, size);
|
||||
} break;
|
||||
case REM_HEADER: {
|
||||
uint32_t size = ReadForwardValue (&dataBuffer);
|
||||
list->RemHeader (data, size);
|
||||
} break;
|
||||
case ADD_TRAILER: {
|
||||
uint32_t size = ReadForwardValue (&dataBuffer);
|
||||
list->AddTrailer (data, size);
|
||||
} break;
|
||||
case REM_TRAILER: {
|
||||
uint32_t size = ReadForwardValue (&dataBuffer);
|
||||
list->RemTrailer (data, size);
|
||||
} break;
|
||||
case ADD_AT_END: {
|
||||
uint32_t nCommands = ReadForwardValue (&dataBuffer);
|
||||
ItemList other;
|
||||
BuildItemList (&other, &dataBuffer, data, nCommands);
|
||||
list->AddAtEnd (&other);
|
||||
} break;
|
||||
case REM_AT_START: {
|
||||
list->RemAtStart (data);
|
||||
} break;
|
||||
case REM_AT_END: {
|
||||
list->RemAtEnd (data);
|
||||
} break;
|
||||
case PADDING_AT_END:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*buffer = dataBuffer;
|
||||
}
|
||||
|
||||
void
|
||||
PacketHistory::PrintDefault (std::ostream &os, Buffer buffer) const
|
||||
{
|
||||
|
@ -865,7 +909,6 @@ PacketHistory::Print (std::ostream &os, Buffer buffer, const PacketPrinter &prin
|
|||
return;
|
||||
}
|
||||
|
||||
PrintComplex (os, buffer, printer);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -39,10 +39,10 @@ class PacketHistory {
|
|||
public:
|
||||
static void Enable (void);
|
||||
|
||||
inline PacketHistory (uint32_t uid, uint32_t size);
|
||||
inline PacketHistory (PacketHistory const &o);
|
||||
inline PacketHistory &operator = (PacketHistory const& o);
|
||||
inline ~PacketHistory ();
|
||||
PacketHistory (uint32_t uid, uint32_t size);
|
||||
PacketHistory (PacketHistory const &o);
|
||||
PacketHistory &operator = (PacketHistory const& o);
|
||||
~PacketHistory ();
|
||||
|
||||
template <typename T>
|
||||
void AddHeader (T const &header, uint32_t size);
|
||||
|
@ -66,57 +66,61 @@ public:
|
|||
static void PrintStats (void);
|
||||
|
||||
private:
|
||||
enum CommandType {
|
||||
INIT = 0,
|
||||
ADD_HEADER = 1,
|
||||
REM_HEADER = 2,
|
||||
ADD_TRAILER = 3,
|
||||
REM_TRAILER = 4,
|
||||
ADD_AT_END = 5,
|
||||
REM_AT_START = 6,
|
||||
REM_AT_END = 7,
|
||||
PADDING_AT_END = 9,
|
||||
LAST
|
||||
struct Data {
|
||||
uint16_t m_count;
|
||||
uint16_t m_size;
|
||||
uint16_t m_dirtyEnd;
|
||||
uint8_t m_data[10];
|
||||
};
|
||||
struct CommandData {
|
||||
uint32_t m_count;
|
||||
uint32_t m_size;
|
||||
uint32_t m_dirtyEnd;
|
||||
uint8_t m_data[8];
|
||||
struct SmallItem {
|
||||
uint16_t next;
|
||||
uint16_t prev;
|
||||
uint32_t typeUid;
|
||||
uint32_t size;
|
||||
uint16_t chunkUid;
|
||||
};
|
||||
typedef std::vector<struct CommandData *> DataFreeList;
|
||||
struct ExtraItem {
|
||||
uint32_t fragmentStart;
|
||||
uint32_t fragmentEnd;
|
||||
uint32_t packetUid;
|
||||
};
|
||||
|
||||
typedef std::vector<struct Data *> DataFreeList;
|
||||
|
||||
PacketHistory ();
|
||||
void Reserve (uint32_t n);
|
||||
inline void Construct (uint32_t uid, uint32_t size);
|
||||
uint32_t GetUleb128Size (uint32_t value) const;
|
||||
void AppendValue (uint32_t value);
|
||||
uint32_t ReadForwardValue (uint8_t **pBuffer) const;
|
||||
uint32_t ReadValue (uint8_t *buffer, uint32_t *n) const;
|
||||
void AppendOneCommand (uint32_t type, uint32_t data);
|
||||
void AppendOneCommand (uint32_t type, uint32_t data0, uint32_t data1);
|
||||
void ReserveCopy (uint32_t size);
|
||||
void AddHeader (uint32_t uid, Chunk const & header, uint32_t size);
|
||||
void RemoveHeader (uint32_t uid, Chunk const & header, uint32_t size);
|
||||
void AddTrailer (uint32_t uid, Chunk const & trailer, uint32_t size);
|
||||
void RemoveTrailer (uint32_t uid, Chunk const & trailer, uint32_t size);
|
||||
void PrintComplex (std::ostream &os, Buffer buffer, const PacketPrinter &printer) const;
|
||||
void BuildItemList (ItemList *list, uint8_t **buffer, uint32_t size, uint32_t n) const;
|
||||
inline bool TryToAppendValue (uint32_t value, uint8_t **buffer);
|
||||
inline bool TryToAppendSmallValue (uint32_t value, uint8_t **buffer);
|
||||
|
||||
static struct PacketHistory::CommandData *Create (uint32_t size);
|
||||
static void Recycle (struct CommandData *data);
|
||||
static struct PacketHistory::CommandData *Allocate (uint32_t n);
|
||||
static void Deallocate (struct CommandData *data);
|
||||
void AddSmall (bool atStart,
|
||||
uint32_t typeUid, uint32_t size);
|
||||
uint32_t GetUleb128Size (uint32_t value) const;
|
||||
uint32_t ReadUleb128 (uint8_t **pBuffer) const;
|
||||
void Append16 (uint16_t value, uint8_t **pBuffer);
|
||||
bool TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end);
|
||||
bool IsZero16 (uint16_t index);
|
||||
bool CanAdd (bool atStart);
|
||||
void ReadSmall (struct PacketHistory::SmallItem *item, uint8_t **pBuffer);
|
||||
void ReadExtra (struct PacketHistory::ExtraItem *item, uint8_t **pBuffer);
|
||||
void Reserve (uint32_t n);
|
||||
void ReserveCopy (uint32_t n);
|
||||
|
||||
static struct PacketHistory::Data *Create (uint32_t size);
|
||||
static void Recycle (struct PacketHistory::Data *data);
|
||||
static struct PacketHistory::Data *Allocate (uint32_t n);
|
||||
static void Deallocate (struct PacketHistory::Data *data);
|
||||
|
||||
static DataFreeList m_freeList;
|
||||
static bool m_enable;
|
||||
static uint32_t m_maxSize;
|
||||
static uint16_t m_chunkUid;
|
||||
|
||||
struct CommandData *m_data;
|
||||
uint32_t m_end;
|
||||
uint32_t m_n;
|
||||
struct Data *m_data;
|
||||
uint16_t m_begin;
|
||||
uint16_t m_end;
|
||||
uint16_t m_used;
|
||||
uint32_t m_packetUid;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
@ -149,72 +153,6 @@ PacketHistory::RemoveTrailer (T const &trailer, uint32_t size)
|
|||
RemoveTrailer (PacketPrinter::GetUid<T> (), trailer, size);
|
||||
}
|
||||
|
||||
|
||||
PacketHistory::PacketHistory (uint32_t uid, uint32_t size)
|
||||
: m_data (0),
|
||||
m_end (0),
|
||||
m_n (0)
|
||||
{
|
||||
Construct (uid, size);
|
||||
}
|
||||
void
|
||||
PacketHistory::Construct (uint32_t uid, uint32_t size)
|
||||
{
|
||||
if (m_enable)
|
||||
{
|
||||
m_data = PacketHistory::Create (0);
|
||||
AppendOneCommand (PacketHistory::INIT,
|
||||
size, uid);
|
||||
}
|
||||
}
|
||||
PacketHistory::PacketHistory (PacketHistory const &o)
|
||||
: m_data (o.m_data),
|
||||
m_end (o.m_end),
|
||||
m_n (o.m_n)
|
||||
{
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->m_count++;
|
||||
}
|
||||
}
|
||||
PacketHistory &
|
||||
PacketHistory::operator = (PacketHistory const& o)
|
||||
{
|
||||
if (m_data == o.m_data)
|
||||
{
|
||||
// self assignment
|
||||
return *this;
|
||||
}
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketHistory::Recycle (m_data);
|
||||
}
|
||||
}
|
||||
m_data = o.m_data;
|
||||
m_end = o.m_end;
|
||||
m_n = o.m_n;
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->m_count++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
PacketHistory::~PacketHistory ()
|
||||
{
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketHistory::Recycle (m_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue