#define MS_CLASS "RTC::SCTP::TLV"
#include "RTC/SCTP/packet/TLV.hpp"
#include "Logger.hpp"
#include "MediaSoupErrors.hpp"
#include <cstring>
#include <limits>
namespace RTC
{
namespace SCTP
{
bool TLV::IsTLV(const uint8_t* buffer, size_t bufferLength, uint16_t& itemLength, uint8_t& padding)
{
MS_TRACE();
if (bufferLength < TLV::TLVHeaderLength)
{
MS_WARN_TAG(sctp, "no space for Header [bufferLength:%zu]", bufferLength);
return false;
}
itemLength = Utils::Byte::Get2Bytes(buffer, 2);
if (itemLength < TLV::TLVHeaderLength)
{
MS_WARN_TAG(
sctp, "Length field must have value greater or equal than %zu", TLV::TLVHeaderLength);
return false;
}
const size_t paddedItemLength = Utils::Byte::PadTo4Bytes(size_t{ itemLength });
if (bufferLength < paddedItemLength)
{
MS_WARN_TAG(
sctp,
"no space for 4-byte padded announced Length [paddedItemLength:%zu, bufferLength:%zu]",
paddedItemLength,
bufferLength);
return false;
}
padding = paddedItemLength - itemLength;
return true;
}
TLV::TLV(uint8_t* buffer, size_t bufferLength) : Serializable(buffer, bufferLength)
{
MS_TRACE();
}
TLV::~TLV()
{
MS_TRACE();
}
void TLV::DumpCommon(int indentation) const
{
MS_TRACE();
MS_DUMP_CLEAN(
indentation,
" length field: %" PRIu16 " (padding: %zu, buffer length: %zu)",
GetLengthField(),
GetLength() - GetLengthField(),
GetBufferLength());
}
void TLV::InitializeTLVHeader(uint16_t lengthFieldValue)
{
MS_TRACE();
SetLengthField(lengthFieldValue);
}
void TLV::SetLengthField(size_t lengthField)
{
MS_TRACE();
if (lengthField > std::numeric_limits<uint16_t>::max())
{
MS_THROW_TYPE_ERROR("lengthField (%zu bytes) cannot be greater than 65535", lengthField);
}
Utils::Byte::Set2Bytes(const_cast<uint8_t*>(GetBuffer()), 2, lengthField);
}
void TLV::SetVariableLengthValue(const uint8_t* value, size_t valueLength)
{
MS_TRACE();
MS_ASSERT(value != nullptr || valueLength == 0, "value cannot be nullptr if valueLength is > 0");
SetVariableLengthValueLength(valueLength);
if (value)
{
std::memmove(GetVariableLengthValuePointer(), value, valueLength);
}
}
void TLV::SetVariableLengthValueLength(size_t valueLength)
{
MS_TRACE();
auto previousLength = GetLength();
auto previousLengthField = GetLengthField();
auto previousValueLength = GetVariableLengthValueLength();
auto newNotPaddedLength =
size_t{ previousLengthField } - size_t{ previousValueLength } + valueLength;
auto newPaddedLength = Utils::Byte::PadTo4Bytes(newNotPaddedLength);
try
{
SetLength(newPaddedLength);
SetLengthField(newNotPaddedLength);
}
catch (const MediaSoupError& error)
{
SetLength(previousLength);
SetLengthField(previousLengthField);
throw;
}
FillPadding(newPaddedLength - newNotPaddedLength);
}
void TLV::AddItem(const TLV* item)
{
MS_TRACE();
auto previousLength = GetLength();
auto previousLengthField = GetLengthField();
try
{
SetLength(previousLength + item->GetLength());
SetLengthField(previousLength + item->GetLengthField());
}
catch (const MediaSoupError& error)
{
SetLength(previousLength);
SetLengthField(previousLengthField);
throw;
}
}
} }