#include "manetMsg.h"
#include "protoDebug.h"
ManetTlv::ManetTlv()
{
}
ManetTlv::~ManetTlv()
{
}
bool ManetTlv::InitIntoBuffer(UINT8 type, void* bufferPtr, unsigned int numBytes)
{
unsigned int minLength = OFFSET_SEMANTICS + 1; if (NULL != bufferPtr)
{
if (numBytes < minLength)
return false;
else
AttachBuffer(bufferPtr, numBytes);
}
else if (buffer_bytes < minLength)
{
return false;
}
((UINT8*)buffer_ptr)[OFFSET_TYPE] = (UINT8)type;
((UINT8*)buffer_ptr)[OFFSET_SEMANTICS] = (UINT8)0;
pkt_length = minLength;
return true;
}
bool ManetTlv::SetExtendedType(UINT8 extType)
{
unsigned int minLength = OFFSET_TYPE_EXT + 1;
if (buffer_bytes < minLength) return false;
SetSemantic(EXTENDED_TYPE);
SetUINT8(OFFSET_TYPE_EXT, extType);
return true;
}
bool ManetTlv::SetIndexRange(UINT8 start, UINT8 stop, bool multivalue, unsigned int numAddrs)
{
ASSERT(start <= stop);
ASSERT((0 == numAddrs) || (stop < numAddrs));
if ((0 != numAddrs) && (0 == start) && (stop == (numAddrs - 1)))
{
unsigned int minLength = OffsetIndexStart();
if (buffer_bytes < minLength) return false;
ClearSemantics(SINGLE_INDEX | MULTI_INDEX | MULTIVALUE);
if (multivalue && (start != stop)) SetSemantic(MULTIVALUE);
pkt_length = minLength;
}
else if (start == stop)
{
unsigned int minLength = OffsetIndexStart() + 1;
if (buffer_bytes < minLength) return false;
ClearSemantics(MULTI_INDEX | MULTIVALUE);
SetSemantic(SINGLE_INDEX);
SetUINT8(OffsetIndexStart(), start);
pkt_length = minLength;
}
else
{
unsigned int minLength = OffsetIndexStart() + 2;
if (buffer_bytes < minLength) return false;
ClearSemantics(SINGLE_INDEX | MULTIVALUE);
SetSemantic(MULTI_INDEX);
if (multivalue) SetSemantic(MULTIVALUE);
SetUINT8(OffsetIndexStart(), start);
SetUINT8(OffsetIndexStop(), stop);
pkt_length = minLength;
}
return true;
}
bool ManetTlv::UpdateIndexRange(UINT8 start, UINT8 stop, bool multivalue, unsigned int numAddrs)
{
ASSERT(start <= stop);
ASSERT((0 == numAddrs) || (stop < numAddrs));
if (start < GetIndexStart())
PLOG(PL_WARN, "ManetTlv::UpdateIndexRange() warning: start index is smaller than current start index.\n");
if ((0 != numAddrs) && (0 == start) && (stop == (numAddrs - 1)))
{
if (HasSingleIndex())
{
unsigned int contentStart = OffsetIndexStart() + 1;
unsigned int contentLength = pkt_length - contentStart;
memmove((char*)buffer_ptr+contentStart-1, (char*)buffer_ptr+contentStart, contentLength);
pkt_length--;
}
else if (HasMultiIndex())
{
unsigned int contentStart = OffsetIndexStart() + 2;
unsigned int contentLength = pkt_length - contentStart;
memmove((char*)buffer_ptr+contentStart-2, (char*)buffer_ptr+contentStart, contentLength);
pkt_length -= 2;
}
ClearSemantics(SINGLE_INDEX | MULTI_INDEX | MULTIVALUE);
if (multivalue && (start != stop)) SetSemantic(MULTIVALUE);
}
else if (start == stop)
{
if (HasMultiIndex())
{
unsigned int contentStart = OffsetIndexStart() + 2;
unsigned int contentLength = pkt_length - contentStart;
memmove((char*)buffer_ptr+contentStart-1, (char*)buffer_ptr+contentStart, contentLength);
pkt_length--;
}
else if (!HasSingleIndex())
{
if ((pkt_length+1) > buffer_bytes) return false;
unsigned int contentStart = OffsetIndexStart();
unsigned int contentLength = pkt_length - contentStart;
memmove((char*)buffer_ptr+contentStart+1, (char*)buffer_ptr+contentStart, contentLength);
pkt_length++;
}
ClearSemantics(MULTI_INDEX | MULTIVALUE);
SetSemantic(SINGLE_INDEX);
SetUINT8(OffsetIndexStart(), start);
}
else
{
if (HasSingleIndex())
{
if ((pkt_length+1) > buffer_bytes) return false; unsigned int contentStart = OffsetIndexStart() + 1;
unsigned int contentLength = pkt_length - contentStart ;
memmove((char*)buffer_ptr+contentStart+1, (char*)buffer_ptr+contentStart, contentLength);
pkt_length++;
}
else if (!HasMultiIndex())
{
if ((pkt_length+2) > buffer_bytes) return false; unsigned int contentStart = OffsetIndexStart();
unsigned int contentLength = pkt_length - contentStart ;
memmove((char*)buffer_ptr+contentStart+2, (char*)buffer_ptr+contentStart, contentLength);
pkt_length++;
}
ClearSemantics(SINGLE_INDEX | MULTIVALUE);
SetSemantic(MULTI_INDEX);
if (multivalue) SetSemantic(MULTIVALUE);
SetUINT8(OffsetIndexStart(), start);
SetUINT8(OffsetIndexStop(), stop);
}
return true;
}
bool ManetTlv::SetValue(const char* value, UINT16 valueLength, int index, unsigned int numAddrs)
{
if (index < 0)
{
if (SemanticIsSet(MULTIVALUE))
{
PLOG(PL_ERROR, "ManetTlv::SetValue() error: can't set non-indexed value for MultiValue TLV\n");
return false;
}
index = 0;
}
else if (HasNoIndex() && !SemanticIsSet(MULTIVALUE))
{
ASSERT(index < 0);
if (index >= 0)
{
PLOG(PL_ERROR, "ManetTlv::SetValue() error: can't set indexed value for NO_INDEX TLV\n");
return false;
}
index = 0; }
else if (SemanticIsSet(SINGLE_INDEX))
{
if (index != GetIndexStart())
{
PLOG(PL_ERROR, "ManetTlv::SetValue() error: can't set multiple values for SINGLE_INDEX TLV\n");
return false;
}
index = 0;
}
else
{
UINT8 startIndex = GetIndexStart();
if ((index < startIndex) || (index > GetIndexStop(numAddrs)))
{
PLOG(PL_ERROR, "ManetTlv::SetValue() error: out-of-range \"index\"\n");
return false; }
else if (SemanticIsSet(MULTIVALUE))
{
index -= startIndex;
}
else
{
PLOG(PL_WARN, "ManetTlv::SetValue() warning: index specified for single value TLV?\n");
index = 0;
}
}
unsigned int offsetValue = OffsetValue();
UINT16 oldTlvLength = GetTlvLength();
unsigned int newTlvOffset = valueLength * index;
UINT16 newTlvLength = newTlvOffset + valueLength;
if (newTlvLength > oldTlvLength)
{
unsigned int newPktLength = offsetValue + newTlvLength;
if ((newTlvLength >= 256) && (!SemanticIsSet(EXTENDED_LENGTH)))
newPktLength++;
if (newPktLength > buffer_bytes)
{
PLOG(PL_WARN, "ManetTlv::SetValue() value length exceeds packet buffer size\n");
return false;
}
if ((newTlvLength >= 256) && (!SemanticIsSet(EXTENDED_LENGTH)))
{
if (0 != oldTlvLength)
{
char* ptrOld = (char*)buffer_ptr + offsetValue;
char* ptrNew = ptrOld + 1;
memmove(ptrNew, ptrOld, oldTlvLength);
}
SetSemantic(EXTENDED_LENGTH);
offsetValue++;
}
SetTlvLength(newTlvLength);
pkt_length = newPktLength;
}
memcpy((char*)buffer_ptr + offsetValue + newTlvOffset, value, valueLength);
if (!SemanticIsSet(HAS_VALUE)) SetSemantic(HAS_VALUE);
return true;
}
void ManetTlv::SetTlvLength(UINT16 tlvLength)
{
if (SemanticIsSet(EXTENDED_LENGTH))
SetUINT16(OffsetLength(), tlvLength);
else if (tlvLength < 256)
SetUINT8(OffsetLength(), (UINT8)tlvLength);
else
PLOG(PL_ERROR, "ManetTlv::SetTlvLength() error: tlvLength exceeds non-extended maximum\n");
}
bool ManetTlv::InitFromBuffer(void* bufferPtr, unsigned numBytes)
{
if (NULL != bufferPtr) AttachBuffer(bufferPtr, numBytes);
UINT8 semantics = (buffer_bytes >= OFFSET_SEMANTICS) ? ((char*)buffer_ptr)[OFFSET_SEMANTICS] : 0;
unsigned int minLength = GetMinLength(semantics);
if (buffer_bytes < minLength)
{
pkt_length = 0;
return false;
}
else
{
pkt_length = minLength + GetTlvLength();
return true;
}
}
UINT16 ManetTlv::GetTlvLength() const
{
if (HasValue())
{
if (HasExtendedLength())
return GetUINT16(OffsetLength());
else
return ((UINT16)GetUINT8(OffsetLength()));
}
else
{
return 0;
}
}
UINT16 ManetTlv::GetValueLength(unsigned int numAddrs) const
{
UINT16 tlvLength = GetTlvLength();
if (IsMultiValue() && (0 != tlvLength))
{
ASSERT(GetIndexStop(numAddrs) >= GetIndexStart());
int numberValues = GetIndexStop(numAddrs) - GetIndexStart() + 1;
if (numberValues > 0)
{
if (0 != (tlvLength % numberValues))
{
PLOG(PL_WARN, "ManetTlv::GetValueLength() TLV value field not integral of num-values\n");
return 0;
}
return (tlvLength / numberValues);
}
else
{
return 0; }
}
else
{
return tlvLength;
}
}
bool ManetTlv::GetValue(char* value, UINT16 valueLength, int index, unsigned int numAddrs) const
{
const char* valuePtr = GetValuePtr(valueLength, index, numAddrs);
if (NULL != valuePtr)
{
memcpy(value, valuePtr, valueLength);
return true;
}
else
{
return false;
}
}
const char* ManetTlv::GetValuePtr(UINT16 valueLength, int index, unsigned int numAddrs) const
{
if (!HasValue())
return NULL;
if (index < 0)
{
if (IsMultiValue())
{
PLOG(PL_ERROR, "ManetTlv::GetValuePtr() error: can't return non-indexed value for MultiValue TLV\n");
return NULL;
}
index = 0;
}
else if (HasNoIndex() && (0 == numAddrs))
{
index = 0; }
else if (HasSingleIndex())
{
if (index != GetIndexStart())
{
PLOG(PL_ERROR, "ManetTlv::GetValuePtr() error: invalid \"index\" for Single Index TLV\n");
return NULL;
}
index = 0;
}
else
{
if (IsMultiValue() || HasIndex())
{
int startIndex = GetIndexStart();
if ((index < startIndex) || (index > GetIndexStop(numAddrs)))
{
PLOG(PL_ERROR, "ManetTlv::GetValuePtr() error: invalid \"index\" out-of-range\n");
return NULL; }
if (IsMultiValue())
index -= startIndex;
else
index = 0;
}
else
{
index = 0; }
}
ASSERT((0 == index) || (valueLength == GetValueLength(numAddrs)));
UINT16 offset = OffsetValue() + (index * valueLength);
if ((offset + valueLength) > pkt_length)
{
PLOG(PL_ERROR, "ManetTlv::GetValuePtr() error: requested value exceeds packet size");
return NULL; }
return ((char*)buffer_ptr + offset);
}
ManetTlvBlock::ManetTlvBlock()
: tlv_pending(false)
{
}
ManetTlvBlock::~ManetTlvBlock()
{
}
bool ManetTlvBlock::InitIntoBuffer(void* bufferPtr, unsigned int numBytes)
{
tlv_pending = false;
if (NULL != bufferPtr)
AttachBuffer(bufferPtr, numBytes);
if (buffer_bytes >= 2)
{
SetTlvBlockLength(0);
pkt_length = 2;
return true;
}
else
{
pkt_length = 0;
return false;
}
}
ManetTlv* ManetTlvBlock::AppendTlv(UINT8 type)
{
if (tlv_pending)
pkt_length += tlv_temp.GetLength();
tlv_pending =
tlv_temp.InitIntoBuffer(type, (char*)buffer_ptr + pkt_length, buffer_bytes - pkt_length);
return tlv_pending ? &tlv_temp : NULL;
}
bool ManetTlvBlock::AppendTlv(ManetTlv& tlv)
{
if (tlv_pending)
{
pkt_length += tlv_temp.GetLength();
tlv_pending = false;
}
unsigned int tlvLength = tlv.GetLength();
unsigned int newLength = pkt_length + tlvLength;
if (buffer_bytes < newLength) return false;
memcpy((char*)buffer_ptr+pkt_length, (char*)tlv.GetBuffer(), tlvLength);
pkt_length += tlvLength;
return true;
}
void ManetTlvBlock::Pack()
{
ASSERT(pkt_length >= 2);
if (tlv_pending)
{
pkt_length += tlv_temp.GetLength();
tlv_pending = false;
}
SetTlvBlockLength(pkt_length - 2);
}
bool ManetTlvBlock::InitFromBuffer(void* bufferPtr, unsigned numBytes)
{
if (NULL != bufferPtr) AttachBuffer(bufferPtr, numBytes);
if (buffer_bytes >= 2)
{
pkt_length = GetTlvBlockLength() + OFFSET_CONTENT;
return true;
}
else
{
pkt_length = 0;
return false;
}
}
bool ManetTlvBlock::GetNextTlv(ManetTlv& tlv) const
{
char* currentBuffer = (char*)tlv.GetBuffer();
unsigned int nextOffset;
if (NULL == currentBuffer)
nextOffset = OFFSET_CONTENT;
else
nextOffset = currentBuffer - (char*)buffer_ptr + tlv.GetLength();
if (nextOffset < pkt_length)
return tlv.InitFromBuffer((char*)buffer_ptr + nextOffset, pkt_length - nextOffset);
else
return false;
}
ManetTlvBlock::Iterator::Iterator(ManetTlvBlock& tlvBlock)
: tlv_block(tlvBlock)
{
}
ManetTlvBlock::Iterator::~Iterator()
{
}
ManetAddrBlock::ManetAddrBlock()
: addr_length(0), tlv_block_pending(false)
{
}
ManetAddrBlock::ManetAddrBlock(void* bufferPtr,
unsigned int numBytes,
bool freeOnDestruct)
: ProtoPkt(bufferPtr, numBytes, freeOnDestruct),
addr_length(0), tlv_block_pending(false)
{
}
ManetAddrBlock::~ManetAddrBlock()
{
}
bool ManetAddrBlock::InitIntoBuffer(void* bufferPtr, unsigned int numBytes, bool freeOnDestruct)
{
unsigned int minLength = 2;
if (NULL != bufferPtr)
AttachBuffer(bufferPtr, numBytes, freeOnDestruct);
if (buffer_bytes < minLength) return false;
addr_length = 0;
SetAddressCount(0);
ClearAllSemantics();
tlv_block.AttachBuffer(NULL, 0);
tlv_block_pending = false;
pkt_length = 2; return true;
} bool ManetAddrBlock::SetHead(const ProtoAddress& addr, UINT8 hlen)
{
ASSERT(addr.IsValid());
if ((hlen < 1) || (hlen > 127) || (hlen > addr.GetLength())) return false;
unsigned int minLength = 3 + hlen;
if (buffer_bytes < minLength) return false;
addr_length = addr.GetLength();
SetSemantic(HAS_HEAD);
SetUINT8(OFFSET_HEAD_LENGTH, hlen);
memcpy((char*)buffer_ptr+ OFFSET_HEAD, addr.GetRawHostAddress(), hlen);
pkt_length = OFFSET_HEAD + hlen; return true;
}
bool ManetAddrBlock::SetTail(const ProtoAddress& addr, UINT8 tlen)
{
if (tlen > addr.GetLength()) return false;
unsigned int hlen = GetHeadLength();
if (0 == hlen)
{
addr_length = addr.GetLength();
}
else if (addr_length != addr.GetLength())
{
return false;
}
unsigned int minLength = 2 + (hlen ? (hlen + 1) : 0) + 1 + tlen;
if (tlen > 0)
{
bool zeroTail = true;
const char* tailPtr = addr.GetRawHostAddress() + addr.GetLength() - tlen;
for (UINT8 i = 0; i < tlen; i++)
{
if (0 != tailPtr[i])
{
zeroTail = false;
break;
}
}
unsigned int offsetTail = OffsetTail();
if (zeroTail)
{
minLength -= tlen;
if (minLength > buffer_bytes) return false;
SetSemantic(HAS_ZERO_TAIL);
pkt_length = offsetTail; }
else
{
if (minLength > buffer_bytes) return false;
memcpy((char*)buffer_ptr + offsetTail, tailPtr, tlen);
pkt_length = offsetTail + tlen; SetSemantic(HAS_FULL_TAIL);
}
SetUINT8(OffsetTailLength(), tlen);
}
else
{
minLength -= 1; ClearSemantic(HAS_ZERO_TAIL);
ClearSemantic(HAS_FULL_TAIL);
pkt_length = HasHead() ? (OFFSET_HEAD + hlen) : (OFFSET_SEMANTICS + 1); }
return true;
}
bool ManetAddrBlock::AppendAddress(const ProtoAddress& addr)
{
if (!HasHead() && !HasTail())
{
addr_length = addr.GetLength();
}
else if (addr.GetLength() != addr_length)
{
PLOG(PL_ERROR,"ManetAddrBlock::AppendAddress() error appending address %s because the address length %d is not equal to the message addr length %d!\n",addr.GetHostString(),addr.GetLength(),addr_length);
return false;
}
UINT8 mlen = GetMidLength();
if (0 == mlen)
{
PLOG(PL_ERROR, "ManetAddrBlock::AppendAddress() error: address mid-length is zero\n");
return false;
}
UINT8 numAddr = GetAddressCount();
unsigned int offset = (0 == numAddr) ? OffsetMid() : pkt_length;
unsigned int minLength = offset + mlen;
if (buffer_bytes < minLength)
{
PLOG(PL_WARN,"ManetAddrBlock::AppendAddress() warn: buffer_bytes(%u) < minLength(%u) no room for packing message\n",buffer_bytes,minLength);
return false;
}
memcpy((char*)buffer_ptr + offset, addr.GetRawHostAddress() + GetHeadLength(), mlen);
((UINT8*)buffer_ptr)[OFFSET_NUM_ADDR]++;
pkt_length = offset + mlen;
return true;
}
bool ManetAddrBlock::SetPrefixLength(UINT8 length, UINT8 index)
{
ASSERT(length <= (GetAddressLength() << 3));
if (0 == GetAddressCount())
{
if ((0 == GetHeadLength()) && (0 == GetTailLength()))
return false;
else
SetAddressCount(1);
}
ASSERT(index < GetAddressCount());
unsigned int offset = OffsetPrefixLength() + index;
unsigned int newLength = offset + 1;
if (newLength > buffer_bytes) return false;
if (!HasPrefixLength() && (0 == index))
{
SetSemantic(HAS_SINGLE_PREFIX_LEN);
}
else if (!HasMultiPrefixLength() && (index > 0))
{
ClearSemantic(HAS_SINGLE_PREFIX_LEN);
SetSemantic(HAS_MULTI_PREFIX_LEN);
}
SetUINT8(offset, length);
if (pkt_length < newLength) pkt_length = newLength;
return true;
}
ManetTlv* ManetAddrBlock::AppendTlv(UINT8 type)
{
if (0 == GetAddressCount())
{
if ((0 == GetHeadLength()) && (0 == GetTailLength()))
return NULL;
else
SetAddressCount(1);
}
if (!tlv_block_pending)
tlv_block_pending = tlv_block.InitIntoBuffer((char*)buffer_ptr + pkt_length, buffer_bytes - pkt_length);
return tlv_block_pending ? tlv_block.AppendTlv(type) : NULL;
}
bool ManetAddrBlock::AppendTlv(ManetTlv& tlv)
{
if (0 == GetAddressCount())
{
if ((0 == GetHeadLength()) && (0 == GetTailLength()))
return false;
else
SetAddressCount(1);
}
if (!tlv_block_pending)
tlv_block_pending = tlv_block.InitIntoBuffer((char*)buffer_ptr + pkt_length, buffer_bytes - pkt_length);
return (tlv_block_pending ? tlv_block.AppendTlv(tlv) : false);
}
void ManetAddrBlock::Pack()
{
if (0 == GetAddressCount())
{
if ((0 == GetHeadLength()) && (0 == GetTailLength()))
{
pkt_length = 0;
return;
}
else
{
SetAddressCount(1);
}
}
if (!tlv_block_pending)
tlv_block.InitIntoBuffer((char*)buffer_ptr + pkt_length, buffer_bytes - pkt_length);
tlv_block.Pack();
pkt_length += tlv_block.GetLength();
tlv_block_pending = false;
}
bool ManetAddrBlock::InitFromBuffer(UINT8 addrLength, void* bufferPtr, unsigned numBytes)
{
if (NULL != bufferPtr) AttachBuffer(bufferPtr, numBytes);
addr_length = addrLength;
pkt_length = 0;
unsigned int minLength = 2;
if (buffer_bytes < minLength) return false;
if (HasHead())
{
minLength +=1;
if (buffer_bytes < minLength) return false;
minLength += GetHeadLength();
if (buffer_bytes < minLength) return false;
}
if (HasTail())
{
minLength += 1;
if (buffer_bytes < minLength) return false;
minLength += HasZeroTail() ? 0 : GetTailLength();
if (buffer_bytes < minLength) return false;
}
minLength += GetAddressCount() * GetMidLength();
if (buffer_bytes < (minLength + 2)) return false;
if (HasPrefixLength())
{
minLength += HasSinglePrefixLength() ? 1 : GetAddressCount();
if (buffer_bytes < minLength) return false;
}
if (tlv_block.InitFromBuffer((char*)buffer_ptr+minLength, buffer_bytes - minLength))
{
pkt_length = minLength + tlv_block.GetLength();
return true;
}
else
{
pkt_length = 0;
return false;
}
}
bool ManetAddrBlock::GetAddress(UINT8 index, ProtoAddress& theAddr) const
{
ASSERT(index < GetAddressCount());
char addrBuffer[16]; UINT8 hlen = GetHeadLength();
ASSERT(hlen <= GetAddressLength());
if (hlen > 0)
memcpy(addrBuffer, (char*)buffer_ptr+OFFSET_HEAD, hlen);
UINT8 mlen = GetMidLength();
ASSERT(mlen <= GetAddressLength());
if (mlen > 0)
memcpy(addrBuffer+hlen, (char*)buffer_ptr + OffsetMid() + index*GetMidLength(), mlen);
UINT8 tlen = GetTailLength();
if (tlen > 0)
{
if (HasZeroTail())
memset(addrBuffer+hlen+mlen, 0, tlen);
else
memcpy(addrBuffer+hlen+mlen, (char*)buffer_ptr + OffsetTail(), tlen);
}
ASSERT((hlen + mlen + tlen) == GetAddressLength());
theAddr.SetRawHostAddress(GetAddressType(), addrBuffer, GetAddressLength());
return theAddr.IsValid();
}
ManetAddrBlock::TlvIterator::TlvIterator(ManetAddrBlock& addrBlk)
: ManetTlvBlock::Iterator(addrBlk.tlv_block)
{
}
ManetAddrBlock::TlvIterator::~TlvIterator()
{
}
ManetMsg::ManetMsg()
{
}
ManetMsg::ManetMsg(void* bufferPtr,
unsigned int numBytes,
bool freeOnDestruct)
: ProtoPkt(bufferPtr, numBytes, freeOnDestruct),
tlv_block_pending(false), addr_block_pending(false)
{
}
ManetMsg::~ManetMsg()
{
}
bool ManetMsg::InitIntoBuffer(void* bufferPtr, unsigned int numBytes)
{
addr_block_pending = false;
if (NULL != bufferPtr)
AttachBuffer(bufferPtr, numBytes);
if (buffer_bytes >= 4)
{
pkt_length = 4;
ClearAllSemantics(); tlv_block_pending = tlv_block.InitIntoBuffer((char*)buffer_ptr+4, buffer_bytes-4);
return tlv_block_pending;
}
else
{
pkt_length = 0;
return false;
}
}
bool ManetMsg::SetOriginator(const ProtoAddress& addr)
{
if (!addr.IsValid())
{
PLOG(PL_ERROR, "ManetMsg::SetOriginator() error: invalid address!\n");
return false;
}
UINT8 addrLen = addr.GetLength();
SetAddressLength(addrLen);
unsigned int offsetOriginator = OffsetOriginator();
if (!HasOriginator())
{
UINT16 newLength = offsetOriginator + addrLen;
if (newLength > buffer_bytes) return false;
tlv_block_pending = tlv_block.InitIntoBuffer((char*)buffer_ptr+newLength, buffer_bytes-newLength);
if (tlv_block_pending)
{
pkt_length = newLength;
SetSemantic(HAS_ORIGINATOR);
}
else
{
return false;
}
}
memcpy((char*)buffer_ptr + offsetOriginator, addr.GetRawHostAddress(), addrLen);
return true;
}
bool ManetMsg::SetHopLimit(UINT8 hopLimit)
{
unsigned int offsetHopLimit = OffsetHopLimit();
if (!HasHopLimit())
{
UINT16 newLength = offsetHopLimit + 1;
if (newLength > buffer_bytes) return false;
tlv_block_pending = tlv_block.InitIntoBuffer((char*)buffer_ptr+newLength, buffer_bytes-newLength);
if (tlv_block_pending)
{
pkt_length = newLength;
SetSemantic(HAS_HOP_LIMIT);
}
else
{
return false;
}
}
SetUINT8(offsetHopLimit, hopLimit);
return true;
}
bool ManetMsg::SetHopCount(UINT8 hopCount)
{
unsigned int offsetHopCount = OffsetHopCount();
if (!HasHopCount())
{
UINT16 newLength = offsetHopCount + 1;
if (newLength > buffer_bytes) return false;
tlv_block_pending = tlv_block.InitIntoBuffer((char*)buffer_ptr+newLength, buffer_bytes-newLength);
if (tlv_block_pending)
{
pkt_length = newLength;
SetSemantic(HAS_HOP_COUNT);
}
else
{
return false;
}
}
SetUINT8(offsetHopCount, hopCount);
return true;
}
bool ManetMsg::SetSequence(UINT16 sequence)
{
unsigned int offsetSequence = OffsetSequence();
if (!HasSequence())
{
UINT16 newLength = offsetSequence + 2;
if (newLength > buffer_bytes) return false;
tlv_block_pending = tlv_block.InitIntoBuffer((char*)buffer_ptr+newLength, buffer_bytes-newLength);
if (tlv_block_pending)
{
pkt_length = newLength;
SetSemantic(HAS_SEQ_NUM);
}
else
{
return false;
}
}
SetUINT8(offsetSequence, sequence);
return true;
}
ManetAddrBlock* ManetMsg::AppendAddressBlock()
{
if (tlv_block_pending)
{
tlv_block.Pack();
pkt_length += tlv_block.GetLength();
tlv_block_pending = false;
}
if (addr_block_pending)
{
addr_block_temp.Pack();
pkt_length += addr_block_temp.GetLength();
}
unsigned int bufferMax = (buffer_bytes > pkt_length) ? buffer_bytes - pkt_length : 0;
char* bufferPtr = (char*)buffer_ptr + pkt_length;
addr_block_pending = addr_block_temp.InitIntoBuffer(bufferPtr, bufferMax);
return (addr_block_pending ? &addr_block_temp : NULL);
}
void ManetMsg::Pack()
{
if (tlv_block_pending)
{
tlv_block.Pack();
pkt_length += tlv_block.GetLength();
tlv_block_pending = false;
}
if (addr_block_pending)
{
addr_block_temp.Pack();
pkt_length += addr_block_temp.GetLength();
addr_block_pending = false;
}
SetMsgSize((UINT16)pkt_length); }
bool ManetMsg::InitFromBuffer(void* bufferPtr, unsigned int numBytes)
{
if (NULL != bufferPtr) AttachBuffer(bufferPtr, numBytes);
if (buffer_bytes < 1) return false; pkt_length = GetMsgSize();
if ((0 == pkt_length) || (pkt_length > buffer_bytes))
{
PLOG(PL_ERROR, "ManetMsg::InitFromBuffer() error: msg size:%u larger than buffer size:%u\n",
pkt_length, buffer_bytes);
pkt_length = 0;
return false;
}
UINT16 tlvBlockOffset = OffsetTlvBlock();
if (pkt_length < tlvBlockOffset)
{
PLOG(PL_ERROR, "ManetMsg::InitFromBuffer() error: msg too short?!\n");
pkt_length = 0;
return false;
}
if (tlv_block.InitFromBuffer((char*)buffer_ptr + tlvBlockOffset, pkt_length - tlvBlockOffset))
{
return true;
}
else
{
PLOG(PL_ERROR, "ManetMsg::InitFromBuffer() error: invalid msg-tlv-block?!\n");
pkt_length = 0;
return false;
}
}
bool ManetMsg::GetOriginator(ProtoAddress& addr) const
{
if (HasOriginator())
{
UINT8 addrLen = GetAddressLength();
addr.SetRawHostAddress(ProtoAddress::GetType(addrLen), (char*)buffer_ptr+OffsetOriginator(),
addrLen);
}
else
{
addr.Invalidate();
}
return addr.IsValid();
}
bool ManetMsg::GetNextAddressBlock(ManetAddrBlock& addrBlk) const
{
char* nextBuffer = (char*)addrBlk.GetBuffer();
if (NULL == nextBuffer)
{
ManetTlvBlock tlvBlk;
if (GetTlvBlock(tlvBlk))
nextBuffer = (char*)tlvBlk.GetBuffer() + tlvBlk.GetLength();
else
return false; }
else
{
nextBuffer += addrBlk.GetLength();
}
unsigned int offset = nextBuffer - (char*)buffer_ptr;
if (offset < pkt_length)
return addrBlk.InitFromBuffer(GetAddressLength(), nextBuffer, pkt_length - offset);
else
return false;
}
ManetMsg::TlvIterator::TlvIterator(ManetMsg& msg)
: ManetTlvBlock::Iterator(msg.tlv_block)
{
}
ManetMsg::TlvIterator::~TlvIterator()
{
}
ManetMsg::AddrBlockIterator::AddrBlockIterator(ManetMsg& theMsg)
: msg(theMsg)
{
}
ManetMsg::AddrBlockIterator::~AddrBlockIterator()
{
}
ManetPkt::ManetPkt()
{
}
ManetPkt::ManetPkt(void* bufferPtr,
unsigned int numBytes,
bool freeOnDestruct)
: ProtoPkt(bufferPtr, numBytes, freeOnDestruct),
tlv_block_pending(false), msg_pending(false)
{
}
ManetPkt::~ManetPkt()
{
}
bool ManetPkt::InitIntoBuffer(void* bufferPtr, unsigned int numBytes)
{
if (NULL != bufferPtr)
AttachBuffer(bufferPtr, numBytes);
if (buffer_bytes < 1) return false;
ClearAllSemantics();
pkt_length = 1;
tlv_block_pending = false;
msg_pending = false;
return true;
}
void ManetPkt::SetVersion(UINT8 version)
{
uint8_t flags = GetUINT8(OFFSET_SEMANTICS) & 0x0F; SetUINT8(OFFSET_SEMANTICS, (version << 4) | flags);
}
void ManetPkt::SetSequence(UINT16 sequence)
{
if (!SemanticIsSet(HAS_SEQ_NUM))
{
SetSemantic(HAS_SEQ_NUM);
pkt_length += 2;
}
SetUINT16(OffsetSequence(), sequence);
}
ManetTlv* ManetPkt::AppendTlv(UINT8 type)
{
if (msg_pending)
return NULL; if (!tlv_block_pending)
{
SetSemantic(HAS_TLV_BLOCK);
unsigned int offsetTlvBlock = OffsetTlvBlock();
tlv_block_pending =
tlv_block.InitIntoBuffer((char*)buffer_ptr+offsetTlvBlock, buffer_bytes-offsetTlvBlock);
}
return (tlv_block_pending ? tlv_block.AppendTlv(type) : NULL);
}
bool ManetPkt::AppendTlv(ManetTlv& tlv)
{
if (msg_pending)
return false; if (!tlv_block_pending)
{
SetSemantic(HAS_TLV_BLOCK);
unsigned int offsetTlvBlock = OffsetTlvBlock();
tlv_block_pending =
tlv_block.InitIntoBuffer((char*)buffer_ptr+offsetTlvBlock, buffer_bytes-offsetTlvBlock);
}
return (tlv_block_pending ? tlv_block.AppendTlv(tlv) : false);
}
ManetMsg* ManetPkt::AppendMessage()
{
if (tlv_block_pending)
{
tlv_block.Pack();
pkt_length += tlv_block.GetLength();
tlv_block_pending = false;
}
if (msg_pending)
{
msg_temp.Pack();
pkt_length += msg_temp.GetLength();
}
unsigned int bufferMax = (buffer_bytes > pkt_length) ? buffer_bytes - pkt_length : 0;
char* bufferPtr = (char*)buffer_ptr + pkt_length;
msg_pending = msg_temp.InitIntoBuffer(bufferPtr, bufferMax);
return msg_pending ? &msg_temp : NULL;
}
bool ManetPkt::AppendMessage(ManetMsg& msg)
{
if (tlv_block_pending)
{
tlv_block.Pack();
pkt_length += tlv_block.GetLength();
tlv_block_pending = false;
}
if (msg_pending)
{
msg_temp.Pack();
pkt_length += msg_temp.GetLength();
}
msg.Pack(); unsigned int msgLength = msg.GetLength();
unsigned int newLength = pkt_length + msgLength;
if (buffer_bytes < newLength) return false;
memcpy((char*)buffer_ptr + pkt_length, (char*)msg.GetBuffer(), msgLength);
pkt_length = newLength;
return true;
}
void ManetPkt::Pack()
{
if (tlv_block_pending)
{
tlv_block.Pack();
pkt_length += tlv_block.GetLength();
tlv_block_pending = false;
}
if (msg_pending)
{
msg_temp.Pack();
pkt_length += msg_temp.GetLength();
msg_pending = false;
}
}
bool ManetPkt::InitFromBuffer(unsigned int pktLength, void* bufferPtr, unsigned int numBytes)
{
if (NULL != bufferPtr)
AttachBuffer(bufferPtr, numBytes);
msg_pending = false;
if ((pktLength < 1) || (buffer_bytes < pktLength))
return false;
if (pktLength < GetMinLength(GetUINT8(OFFSET_SEMANTICS)))
return false;
else
pkt_length = pktLength;
if (HasTlvBlock())
{
unsigned tlvBlockOffset = OffsetTlvBlock();
char* tlvBuffer = (char*)buffer_ptr + tlvBlockOffset;
return tlv_block.InitFromBuffer(tlvBuffer, pkt_length - tlvBlockOffset);
}
else
{
tlv_block.InitFromBuffer(NULL, 0);
return true;
}
}
bool ManetPkt::GetNextMessage(ManetMsg& msg)
{
char* currentBuffer = (char*)msg.GetBuffer();
char* nextBuffer = currentBuffer ?
(currentBuffer + msg.GetLength()) :
((char*)buffer_ptr + OffsetPayload());
unsigned int nextOffset = nextBuffer - (char*)buffer_ptr;
if (nextOffset < pkt_length)
{
return msg.InitFromBuffer(nextBuffer, pkt_length - nextOffset);
}
else
return false; }
ManetPkt::TlvIterator::TlvIterator(ManetPkt& pkt)
: ManetTlvBlock::Iterator(pkt.tlv_block)
{
}
ManetPkt::TlvIterator::~TlvIterator()
{
}
ManetPkt::MsgIterator::MsgIterator(ManetPkt& thePkt)
: pkt(thePkt)
{
}
ManetPkt::MsgIterator::~MsgIterator()
{
}