/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2005,2006,2007 INRIA * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Mathieu Lacage */ #include "buffer.h" #include "ns3/assert.h" #include "ns3/log.h" NS_LOG_COMPONENT_DEFINE ("Buffer"); #define LOG_INTERNAL_STATE(y) \ NS_LOG_LOGIC (y << "start="< BufferDataList; static struct BufferData *BufferAllocate (uint32_t reqSize); static void BufferDeallocate (struct BufferData *data); } // namespace ns3 namespace ns3 { #ifdef BUFFER_HEURISTICS /* The following macros are pretty evil but they are needed to allow us to * keep track of 3 possible states for the g_freeList variable: * - uninitialized means that no one has created a buffer yet * so no one has created the associated free list (it is created * on-demand when the first buffer is created) * - initialized means that the free list exists and is valid * - destroyed means that the static destructors of this compilation unit * have run so, the free list has been cleared from its content * The key is that in destroyed state, we are careful not re-create it * which is a typical weakness of lazy evaluation schemes which use * '0' as a special value to indicate both un-initialized and destroyed. * Note that it is important to use '0' as the marker for un-initialized state * because the variable holding this state information is initialized to zero * which the compiler assigns to zero-memory which is initialized to _zero_ * before the constructors run so this ensures perfect handling of crazy * constructor orderings. */ #define MAGIC_DESTROYED (~(long) 0) #define IS_UNINITIALIZED(x) (x == (BufferDataList*)0) #define IS_DESTROYED(x) (x == (BufferDataList*)MAGIC_DESTROYED) #define IS_INITIALIZED(x) (!IS_UNINITIALIZED(x) && !IS_DESTROYED(x)) #define DESTROYED ((BufferDataList*)MAGIC_DESTROYED) #define UNINITIALIZED ((BufferDataList*)0) static uint32_t g_recommendedStart = 0; static uint64_t g_nAddNoRealloc = 0; static uint64_t g_nAddRealloc = 0; static BufferDataList *g_freeList = 0; static uint32_t g_maxSize = 0; static uint64_t g_nAllocs = 0; static uint64_t g_nCreates = 0; #endif /* BUFFER_HEURISTICS */ static struct LocalStaticDestructor { ~LocalStaticDestructor(void) { #ifdef PRINT_STATS #ifdef BUFFER_HEURISTICS double efficiency; efficiency = g_nAllocs; efficiency /= g_nCreates; std::cout <<"buffer free list efficiency="<m_size, g_recommendedStart); m_maxZeroAreaStart = m_start; #else m_start = 0; #endif /* BUFFER_HEURISTICS */ m_zeroAreaStart = m_start; m_zeroAreaEnd = m_zeroAreaStart + zeroSize; m_end = m_zeroAreaEnd; m_data->m_dirtyStart = m_start; m_data->m_dirtyEnd = m_end; NS_ASSERT (CheckInternalState ()); } Buffer::Buffer (Buffer const&o) : m_data (o.m_data), #ifdef BUFFER_HEURISTICS m_maxZeroAreaStart (o.m_zeroAreaStart), #endif m_zeroAreaStart (o.m_zeroAreaStart), m_zeroAreaEnd (o.m_zeroAreaEnd), m_start (o.m_start), m_end (o.m_end) { NS_LOG_FUNCTION (this << &o); m_data->m_count++; NS_ASSERT (CheckInternalState ()); } Buffer & Buffer::operator = (Buffer const&o) { NS_LOG_FUNCTION (this << &o); NS_ASSERT (CheckInternalState ()); if (m_data != o.m_data) { // not assignment to self. m_data->m_count--; if (m_data->m_count == 0) { Recycle (m_data); } m_data = o.m_data; m_data->m_count++; } HEURISTICS ( g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart); m_maxZeroAreaStart = o.m_maxZeroAreaStart; ); m_zeroAreaStart = o.m_zeroAreaStart; m_zeroAreaEnd = o.m_zeroAreaEnd; m_start = o.m_start; m_end = o.m_end; NS_ASSERT (CheckInternalState ()); return *this; } Buffer::~Buffer () { NS_LOG_FUNCTION (this); NS_ASSERT (CheckInternalState ()); HEURISTICS (g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart)); m_data->m_count--; if (m_data->m_count == 0) { Recycle (m_data); } } Buffer::Iterator Buffer::Begin (void) const { NS_ASSERT (CheckInternalState ()); return Buffer::Iterator (this); } Buffer::Iterator Buffer::End (void) const { NS_ASSERT (CheckInternalState ()); return Buffer::Iterator (this, false); } uint32_t Buffer::GetInternalSize (void) const { return m_zeroAreaStart - m_start + m_end - m_zeroAreaEnd; } uint32_t Buffer::GetInternalEnd (void) const { return m_end - (m_zeroAreaEnd - m_zeroAreaStart); } bool Buffer::AddAtStart (uint32_t start) { NS_LOG_FUNCTION (this << start); bool dirty; NS_ASSERT (CheckInternalState ()); bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart; if (m_start >= start && !isDirty) { /* enough space in the buffer and not dirty. * To add: |..| * Before: |*****---------***| * After: |***..---------***| */ NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart); m_start -= start; dirty = m_start > m_data->m_dirtyStart; // update dirty area m_data->m_dirtyStart = m_start; HEURISTICS (g_nAddNoRealloc++); } else { uint32_t newSize = GetInternalSize () + start; struct BufferData *newData = Buffer::Create (newSize); memcpy (newData->m_data + start, m_data->m_data + m_start, GetInternalSize ()); m_data->m_count--; if (m_data->m_count == 0) { Buffer::Recycle (m_data); } m_data = newData; int32_t delta = start - m_start; m_start += delta; m_zeroAreaStart += delta; m_zeroAreaEnd += delta; m_end += delta; m_start -= start; // update dirty area m_data->m_dirtyStart = m_start; m_data->m_dirtyEnd = m_end; dirty = true; HEURISTICS (g_nAddRealloc++); } HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart)); LOG_INTERNAL_STATE ("add start=" << start << ", "); NS_ASSERT (CheckInternalState ()); return dirty; } bool Buffer::AddAtEnd (uint32_t end) { NS_LOG_FUNCTION (this << end); bool dirty; NS_ASSERT (CheckInternalState ()); bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd; if (GetInternalEnd () + end <= m_data->m_size && !isDirty) { /* enough space in buffer and not dirty * Add: |...| * Before: |**----*****| * After: |**----...**| */ NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd); m_end += end; // update dirty area. m_data->m_dirtyEnd = m_end; dirty = m_end < m_data->m_dirtyEnd; HEURISTICS (g_nAddNoRealloc++); } else { uint32_t newSize = GetInternalSize () + end; struct BufferData *newData = Buffer::Create (newSize); memcpy (newData->m_data, m_data->m_data + m_start, GetInternalSize ()); m_data->m_count--; if (m_data->m_count == 0) { Buffer::Recycle (m_data); } m_data = newData; int32_t delta = -m_start; m_zeroAreaStart += delta; m_zeroAreaEnd += delta; m_end += delta; m_start += delta; m_end += end; // update dirty area m_data->m_dirtyStart = m_start; m_data->m_dirtyEnd = m_end; dirty = true; HEURISTICS (g_nAddRealloc++); } HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart)); LOG_INTERNAL_STATE ("add end=" << end << ", "); NS_ASSERT (CheckInternalState ()); return dirty; } void Buffer::AddAtEnd (const Buffer &o) { NS_LOG_FUNCTION (this << &o); if (m_data->m_count == 1 && m_end == m_zeroAreaEnd && m_end == m_data->m_dirtyEnd && o.m_start == o.m_zeroAreaStart && o.m_zeroAreaEnd - o.m_zeroAreaStart > 0) { /** * This is an optimization which kicks in when * we attempt to aggregate two buffers which contain * adjacent zero areas. */ uint32_t zeroSize = o.m_zeroAreaEnd - o.m_zeroAreaStart; m_zeroAreaEnd += zeroSize; m_end = m_zeroAreaEnd; m_data->m_dirtyEnd = m_zeroAreaEnd; uint32_t endData = o.m_end - o.m_zeroAreaEnd; AddAtEnd (endData); Buffer::Iterator dst = End (); dst.Prev (endData); Buffer::Iterator src = o.End (); src.Prev (endData); dst.Write (src, o.End ()); NS_ASSERT (CheckInternalState ()); return; } Buffer dst = CreateFullCopy (); Buffer src = o.CreateFullCopy (); dst.AddAtEnd (src.GetSize ()); Buffer::Iterator destStart = dst.End (); destStart.Prev (src.GetSize ()); destStart.Write (src.Begin (), src.End ()); *this = dst; NS_ASSERT (CheckInternalState ()); } void Buffer::RemoveAtStart (uint32_t start) { NS_LOG_FUNCTION (this << start); NS_ASSERT (CheckInternalState ()); uint32_t newStart = m_start + start; if (newStart <= m_zeroAreaStart) { /* only remove start of buffer */ m_start = newStart; } else if (newStart <= m_zeroAreaEnd) { /* remove start of buffer _and_ start of zero area */ uint32_t delta = newStart - m_zeroAreaStart; m_start = m_zeroAreaStart; m_zeroAreaEnd -= delta; m_end -= delta; } else if (newStart <= m_end) { /* remove start of buffer, complete zero area, and part * of end of buffer */ NS_ASSERT (m_end >= start); uint32_t zeroSize = m_zeroAreaEnd - m_zeroAreaStart; m_start = newStart - zeroSize; m_end -= zeroSize; m_zeroAreaStart = m_start; m_zeroAreaEnd = m_start; } else { /* remove all buffer */ m_end -= m_zeroAreaEnd - m_zeroAreaStart; m_start = m_end; m_zeroAreaEnd = m_end; m_zeroAreaStart = m_end; } HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart)); LOG_INTERNAL_STATE ("rem start=" << start << ", "); NS_ASSERT (CheckInternalState ()); } void Buffer::RemoveAtEnd (uint32_t end) { NS_LOG_FUNCTION (this << end); NS_ASSERT (CheckInternalState ()); uint32_t newEnd = m_end - std::min (end, m_end - m_start); if (newEnd > m_zeroAreaEnd) { /* remove part of end of buffer */ m_end = newEnd; } else if (newEnd > m_zeroAreaStart) { /* remove end of buffer, part of zero area */ m_end = newEnd; m_zeroAreaEnd = newEnd; } else if (newEnd > m_start) { /* remove end of buffer, zero area, part of start of buffer */ m_end = newEnd; m_zeroAreaEnd = newEnd; m_zeroAreaStart = newEnd; } else { /* remove all buffer */ m_end = m_start; m_zeroAreaEnd = m_start; m_zeroAreaStart = m_start; } HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart)); LOG_INTERNAL_STATE ("rem end=" << end << ", "); NS_ASSERT (CheckInternalState ()); } Buffer Buffer::CreateFragment (uint32_t start, uint32_t length) const { NS_LOG_FUNCTION (this << start << length); NS_ASSERT (CheckInternalState ()); Buffer tmp = *this; tmp.RemoveAtStart (start); tmp.RemoveAtEnd (GetSize () - (start + length)); NS_ASSERT (CheckInternalState ()); return tmp; } Buffer Buffer::CreateFullCopy (void) const { NS_LOG_FUNCTION (this); NS_ASSERT (CheckInternalState ()); if (m_zeroAreaEnd - m_zeroAreaStart != 0) { Buffer tmp; tmp.AddAtStart (m_zeroAreaEnd - m_zeroAreaStart); tmp.Begin ().WriteU8 (0, m_zeroAreaEnd - m_zeroAreaStart); uint32_t dataStart = m_zeroAreaStart - m_start; tmp.AddAtStart (dataStart); tmp.Begin ().Write (m_data->m_data+m_start, dataStart); uint32_t dataEnd = m_end - m_zeroAreaEnd; tmp.AddAtEnd (dataEnd); Buffer::Iterator i = tmp.End (); i.Prev (dataEnd); i.Write (m_data->m_data+m_zeroAreaStart,dataEnd); NS_ASSERT (tmp.CheckInternalState ()); return tmp; } NS_ASSERT (CheckInternalState ()); return *this; } uint32_t Buffer::GetSerializedSize (void) const { uint32_t dataStart = (m_zeroAreaStart - m_start + 3) & (~0x3); uint32_t dataEnd = (m_end - m_zeroAreaEnd + 3) & (~0x3); // total size 4-bytes for dataStart length // + X number of bytes for dataStart // + 4-bytes for dataEnd length // + X number of bytes for dataEnd uint32_t sz = sizeof (uint32_t) + sizeof (uint32_t) + dataStart + sizeof (uint32_t) + dataEnd; return sz; } uint32_t Buffer::Serialize (uint8_t* buffer, uint32_t maxSize) const { uint32_t* p = reinterpret_cast (buffer); uint32_t size = 0; NS_LOG_FUNCTION (this); // Add the zero data length if (size + 4 <= maxSize) { size += 4; *p++ = m_zeroAreaEnd - m_zeroAreaStart; } else { return 0; } // Add the length of actual start data uint32_t dataStartLength = m_zeroAreaStart - m_start; if (size + 4 <= maxSize) { size += 4; *p++ = dataStartLength; } else { return 0; } // Add the actual data if (size + ((dataStartLength + 3) & (~3)) <= maxSize) { size += (dataStartLength + 3) & (~3); memcpy(p, m_data->m_data + m_start, dataStartLength); p += (((dataStartLength + 3) & (~3))/4); // Advance p, insuring 4 byte boundary } else { return 0; } // Add the length of the actual end data uint32_t dataEndLength = m_end - m_zeroAreaEnd; if (size + 4 <= maxSize) { size += 4; *p++ = dataEndLength; } else { return 0; } // Add the actual data if (size + ((dataEndLength + 3) & (~3)) <= maxSize) { size += (dataEndLength + 3) & (~3); memcpy(p, m_data->m_data+m_zeroAreaStart,dataEndLength); p += (((dataEndLength + 3) & (~3))/4); // Advance p, insuring 4 byte boundary } else { return 0; } // Serialzed everything successfully return 1; } uint32_t Buffer::Deserialize (const uint8_t *buffer, uint32_t size) { const uint32_t* p = reinterpret_cast (buffer); uint32_t sizeCheck = size-4; NS_ASSERT (sizeCheck >= 4); uint32_t zeroDataLength = *p++; sizeCheck -= 4; // Create zero bytes Initialize (zeroDataLength); // Add start data NS_ASSERT (sizeCheck >= 4); uint32_t dataStartLength = *p++; sizeCheck -= 4; AddAtStart (dataStartLength); NS_ASSERT (sizeCheck >= dataStartLength); Begin ().Write (reinterpret_cast (const_cast (p)), dataStartLength); p += (((dataStartLength+3)&(~3))/4); // Advance p, insuring 4 byte boundary sizeCheck -= ((dataStartLength+3)&(~3)); // Add end data NS_ASSERT (sizeCheck >= 4); uint32_t dataEndLength = *p++; sizeCheck -= 4; AddAtEnd (dataEndLength); NS_ASSERT (sizeCheck >= dataEndLength); Buffer::Iterator tmp = End (); tmp.Prev (dataEndLength); tmp.Write (reinterpret_cast (const_cast (p)), dataEndLength); p += (((dataEndLength+3)&(~3))/4); // Advance p, insuring 4 byte boundary sizeCheck -= ((dataEndLength+3)&(~3)); NS_ASSERT (sizeCheck == 0); // return zero if buffer did not // contain a complete message return (sizeCheck != 0) ? 0 : 1; } int32_t Buffer::GetCurrentStartOffset (void) const { return m_start; } int32_t Buffer::GetCurrentEndOffset (void) const { return m_end; } void Buffer::TransformIntoRealBuffer (void) const { NS_ASSERT (CheckInternalState ()); Buffer tmp = CreateFullCopy (); *const_cast (this) = tmp; NS_ASSERT (CheckInternalState ()); } uint8_t const* Buffer::PeekData (void) const { NS_ASSERT (CheckInternalState ()); TransformIntoRealBuffer (); NS_ASSERT (CheckInternalState ()); return m_data->m_data + m_start; } void Buffer::CopyData(std::ostream *os, uint32_t size) const { if (size > 0) { uint32_t tmpsize = std::min (m_zeroAreaStart-m_start, size); os->write((const char*)(m_data->m_data + m_start), tmpsize); if (size > tmpsize) { size -= m_zeroAreaStart-m_start; tmpsize = std::min (m_zeroAreaEnd - m_zeroAreaStart, size); uint32_t left = tmpsize; while (left > 0) { uint32_t toWrite = std::min (left, g_zeroes.size); os->write (g_zeroes.buffer, toWrite); left -= toWrite; } if (size > tmpsize) { size -= tmpsize; tmpsize = std::min (m_end - m_zeroAreaEnd, size); os->write ((const char*)(m_data->m_data + m_zeroAreaStart), tmpsize); } } } } uint32_t Buffer::CopyData (uint8_t *buffer, uint32_t size) const { uint32_t originalSize = size; if (size > 0) { uint32_t tmpsize = std::min (m_zeroAreaStart-m_start, size); memcpy (buffer, (const char*)(m_data->m_data + m_start), tmpsize); buffer += tmpsize; if (size > tmpsize) { size -= m_zeroAreaStart-m_start; tmpsize = std::min (m_zeroAreaEnd - m_zeroAreaStart, size); uint32_t left = tmpsize; while (left > 0) { uint32_t toWrite = std::min (left, g_zeroes.size); memcpy (buffer, g_zeroes.buffer, toWrite); left -= toWrite; buffer += toWrite; } if (size > tmpsize) { size -= tmpsize; tmpsize = std::min (m_end - m_zeroAreaEnd, size); memcpy (buffer, (const char*)(m_data->m_data + m_zeroAreaStart), tmpsize); } } } return originalSize - size; } /****************************************************** * The buffer iterator below. ******************************************************/ Buffer::Iterator::Iterator () : m_zeroStart (0), m_zeroEnd (0), m_dataStart (0), m_dataEnd (0), m_current (0), m_data (0) { } Buffer::Iterator::Iterator (Buffer const*buffer) { Construct (buffer); m_current = m_dataStart; } Buffer::Iterator::Iterator (Buffer const*buffer, bool dummy) { Construct (buffer); m_current = m_dataEnd; } void Buffer::Iterator::Construct (const Buffer *buffer) { m_zeroStart = buffer->m_zeroAreaStart; m_zeroEnd = buffer->m_zeroAreaEnd; m_dataStart = buffer->m_start; m_dataEnd = buffer->m_end; m_data = buffer->m_data->m_data; } void Buffer::Iterator::Next (void) { NS_ASSERT (m_current + 1 <= m_dataEnd); m_current++; } void Buffer::Iterator::Prev (void) { NS_ASSERT (m_current >= 1); m_current--; } void Buffer::Iterator::Next (uint32_t delta) { NS_ASSERT (m_current + delta <= m_dataEnd); m_current += delta; } void Buffer::Iterator::Prev (uint32_t delta) { NS_ASSERT (m_current >= delta); m_current -= delta; } uint32_t Buffer::Iterator::GetDistanceFrom (Iterator const &o) const { NS_ASSERT (m_data == o.m_data); int32_t diff = m_current - o.m_current; if (diff < 0) { return -diff; } else { return diff; } } bool Buffer::Iterator::IsEnd (void) const { return m_current == m_dataEnd; } bool Buffer::Iterator::IsStart (void) const { return m_current == m_dataStart; } bool Buffer::Iterator::CheckNoZero (uint32_t start, uint32_t end) const { bool ok = true; for (uint32_t i = start; i < end; i++) { if (!Check (i)) { ok = false; } } return ok; } bool Buffer::Iterator::Check (uint32_t i) const { return i >= m_dataStart && !(i >= m_zeroStart && i < m_zeroEnd) && i <= m_dataEnd; } void Buffer::Iterator::Write (Iterator start, Iterator end) { NS_ASSERT (start.m_data == end.m_data); NS_ASSERT (start.m_current <= end.m_current); NS_ASSERT (start.m_zeroStart == end.m_zeroStart); NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd); NS_ASSERT (m_data != start.m_data); uint32_t size = end.m_current - start.m_current; Iterator cur = start; NS_ASSERT_MSG (CheckNoZero (m_current, m_current + size), GetWriteErrorMessage ()); if (start.m_current <= start.m_zeroStart) { uint32_t toCopy = std::min (size, start.m_zeroStart - start.m_current); memcpy (&m_data[m_current], &start.m_data[start.m_current], toCopy); start.m_current += toCopy; m_current += toCopy; size -= toCopy; } if (start.m_current <= start.m_zeroEnd) { uint32_t toCopy = std::min (size, start.m_zeroEnd - start.m_current); memset (&m_data[m_current], 0, toCopy); start.m_current += toCopy; m_current += toCopy; size -= toCopy; } uint32_t toCopy = std::min (size, start.m_dataEnd - start.m_current); uint8_t *from = &start.m_data[start.m_current - (start.m_zeroEnd-start.m_zeroStart)]; uint8_t *to = &m_data[m_current]; memcpy (to, from, toCopy); m_current += toCopy; } void Buffer::Iterator::WriteU16 (uint16_t data) { WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); } void Buffer::Iterator::WriteU32 (uint32_t data) { WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); } void Buffer::Iterator::WriteU64 (uint64_t data) { WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); data >>= 8; WriteU8 (data & 0xff); } void Buffer::Iterator::WriteHtolsbU16 (uint16_t data) { WriteU8 ((data >> 0) & 0xff); WriteU8 ((data >> 8) & 0xff); } void Buffer::Iterator::WriteHtolsbU32 (uint32_t data) { WriteU8 ((data >> 0) & 0xff); WriteU8 ((data >> 8) & 0xff); WriteU8 ((data >> 16) & 0xff); WriteU8 ((data >> 24) & 0xff); } void Buffer::Iterator::WriteHtolsbU64 (uint64_t data) { WriteU8 ((data >> 0) & 0xff); WriteU8 ((data >> 8) & 0xff); WriteU8 ((data >> 16) & 0xff); WriteU8 ((data >> 24) & 0xff); WriteU8 ((data >> 32) & 0xff); WriteU8 ((data >> 40) & 0xff); WriteU8 ((data >> 48) & 0xff); WriteU8 ((data >> 56) & 0xff); } void Buffer::Iterator::WriteHtonU64 (uint64_t data) { WriteU8 ((data >> 56) & 0xff); WriteU8 ((data >> 48) & 0xff); WriteU8 ((data >> 40) & 0xff); WriteU8 ((data >> 32) & 0xff); WriteU8 ((data >> 24) & 0xff); WriteU8 ((data >> 16) & 0xff); WriteU8 ((data >> 8) & 0xff); WriteU8 ((data >> 0) & 0xff); } void Buffer::Iterator::Write (uint8_t const*buffer, uint32_t size) { NS_ASSERT_MSG (CheckNoZero (m_current, size), GetWriteErrorMessage ()); uint8_t *to; if (m_current <= m_zeroStart) { to = &m_data[m_current]; } else { to = &m_data[m_current - (m_zeroEnd - m_zeroStart)]; } memcpy (to, buffer, size); m_current += size; } uint16_t Buffer::Iterator::ReadU16 (void) { uint8_t byte0 = ReadU8 (); uint8_t byte1 = ReadU8 (); uint16_t data = byte1; data <<= 8; data |= byte0; return data; } uint32_t Buffer::Iterator::ReadU32 (void) { uint8_t byte0 = ReadU8 (); uint8_t byte1 = ReadU8 (); uint8_t byte2 = ReadU8 (); uint8_t byte3 = ReadU8 (); uint32_t data = byte3; data <<= 8; data |= byte2; data <<= 8; data |= byte1; data <<= 8; data |= byte0; return data; } uint64_t Buffer::Iterator::ReadU64 (void) { uint8_t byte0 = ReadU8 (); uint8_t byte1 = ReadU8 (); uint8_t byte2 = ReadU8 (); uint8_t byte3 = ReadU8 (); uint8_t byte4 = ReadU8 (); uint8_t byte5 = ReadU8 (); uint8_t byte6 = ReadU8 (); uint8_t byte7 = ReadU8 (); uint64_t data = byte7; data <<= 8; data |= byte6; data <<= 8; data |= byte5; data <<= 8; data |= byte4; data <<= 8; data |= byte3; data <<= 8; data |= byte2; data <<= 8; data |= byte1; data <<= 8; data |= byte0; return data; } uint16_t Buffer::Iterator::SlowReadNtohU16 (void) { uint16_t retval = 0; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); return retval; } uint32_t Buffer::Iterator::SlowReadNtohU32 (void) { uint32_t retval = 0; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); return retval; } uint64_t Buffer::Iterator::ReadNtohU64 (void) { uint64_t retval = 0; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); retval <<= 8; retval |= ReadU8 (); return retval; } uint16_t Buffer::Iterator::ReadLsbtohU16 (void) { uint8_t byte0 = ReadU8 (); uint8_t byte1 = ReadU8 (); uint16_t data = byte1; data <<= 8; data |= byte0; return data; } uint32_t Buffer::Iterator::ReadLsbtohU32 (void) { uint8_t byte0 = ReadU8 (); uint8_t byte1 = ReadU8 (); uint8_t byte2 = ReadU8 (); uint8_t byte3 = ReadU8 (); uint32_t data = byte3; data <<= 8; data |= byte2; data <<= 8; data |= byte1; data <<= 8; data |= byte0; return data; } uint64_t Buffer::Iterator::ReadLsbtohU64 (void) { uint8_t byte0 = ReadU8 (); uint8_t byte1 = ReadU8 (); uint8_t byte2 = ReadU8 (); uint8_t byte3 = ReadU8 (); uint8_t byte4 = ReadU8 (); uint8_t byte5 = ReadU8 (); uint8_t byte6 = ReadU8 (); uint8_t byte7 = ReadU8 (); uint64_t data = byte7; data <<= 8; data |= byte6; data <<= 8; data |= byte5; data <<= 8; data |= byte4; data <<= 8; data |= byte3; data <<= 8; data |= byte2; data <<= 8; data |= byte1; data <<= 8; data |= byte0; return data; } void Buffer::Iterator::Read (uint8_t *buffer, uint32_t size) { for (uint32_t i = 0; i < size; i++) { buffer[i] = ReadU8 (); } } uint16_t Buffer::Iterator::CalculateIpChecksum(uint16_t size) { return CalculateIpChecksum(size, 0); } uint16_t Buffer::Iterator::CalculateIpChecksum(uint16_t size, uint32_t initialChecksum) { /* see RFC 1071 to understand this code. */ uint32_t sum = initialChecksum; for (int j = 0; j < size/2; j++) sum += ReadU16 (); if (size & 1) sum += ReadU8 (); while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); return ~sum; } uint32_t Buffer::Iterator::GetSize (void) const { return m_dataEnd - m_dataStart; } std::string Buffer::Iterator::GetReadErrorMessage (void) const { std::string str = "You have attempted to read beyond the bounds of the " "available buffer space. This usually indicates that a " "Header::Deserialize or Trailer::Deserialize method " "is trying to read data which was not written by " "a Header::Serialize or Trailer::Serialize method. " "In short: check the code of your Serialize and Deserialize " "methods."; return str; } std::string Buffer::Iterator::GetWriteErrorMessage (void) const { std::string str; if (m_current < m_dataStart) { str = "You have attempted to write before the start of the available " "buffer space. This usually indicates that Trailer::GetSerializedSize " "returned a size which is too small compared to what Trailer::Serialize " "is actually using."; } else if (m_current >= m_dataEnd) { str = "You have attempted to write after the end of the available " "buffer space. This usually indicates that Header::GetSerializedSize " "returned a size which is too small compared to what Header::Serialize " "is actually using."; } else { NS_ASSERT (m_current >= m_zeroStart && m_current < m_zeroEnd); str = "You have attempted to write inside the payload area of the " "buffer. This usually indicates that your Serialize method uses more " "buffer space than what your GetSerialized method returned."; } return str; } } // namespace ns3