#define MS_CLASS "RTC::SCTP::Packet"
#include "RTC/SCTP/association/StateCookie.hpp"
#include "Logger.hpp"
#include "MediaSoupErrors.hpp"
namespace RTC
{
namespace SCTP
{
bool StateCookie::IsMediasoupStateCookie(const uint8_t* buffer, size_t bufferLength)
{
MS_TRACE();
if (bufferLength != StateCookie::StateCookieLength)
{
return false;
}
if (Utils::Byte::Get8Bytes(buffer, 0) != StateCookie::Magic1)
{
return false;
}
auto* negotiatedCapabilitiesField = reinterpret_cast<NegotiatedCapabilitiesField*>(
const_cast<uint8_t*>(buffer) + StateCookie::NegotiatedCapabilitiesOffset);
if (ntohs(negotiatedCapabilitiesField->magic2) != StateCookie::Magic2)
{
return false;
}
return true;
}
StateCookie* StateCookie::Parse(const uint8_t* buffer, size_t bufferLength)
{
MS_TRACE();
if (!StateCookie::IsMediasoupStateCookie(buffer, bufferLength))
{
MS_WARN_TAG(sctp, "not a StateCookie generated by mediasoup");
return nullptr;
}
auto* stateCookie = new StateCookie(const_cast<uint8_t*>(buffer), bufferLength);
return stateCookie;
}
StateCookie* StateCookie::Factory(
uint8_t* buffer,
size_t bufferLength,
uint32_t localVerificationTag,
uint32_t remoteVerificationTag,
uint32_t localInitialTsn,
uint32_t remoteInitialTsn,
uint32_t remoteAdvertisedReceiverWindowCredit,
uint64_t tieTag,
const NegotiatedCapabilities& negotiatedCapabilities)
{
MS_TRACE();
StateCookie::Write(
buffer,
bufferLength,
localVerificationTag,
remoteVerificationTag,
localInitialTsn,
remoteInitialTsn,
remoteAdvertisedReceiverWindowCredit,
tieTag,
negotiatedCapabilities);
return new StateCookie(buffer, StateCookie::StateCookieLength);
}
void StateCookie::Write(
uint8_t* buffer,
size_t bufferLength,
uint32_t localVerificationTag,
uint32_t remoteVerificationTag,
uint32_t localInitialTsn,
uint32_t remoteInitialTsn,
uint32_t remoteAdvertisedReceiverWindowCredit,
uint64_t tieTag,
const NegotiatedCapabilities& negotiatedCapabilities)
{
MS_TRACE();
if (bufferLength < StateCookie::StateCookieLength)
{
MS_THROW_TYPE_ERROR("buffer too small");
}
Utils::Byte::Set8Bytes(buffer, 0, StateCookie::Magic1);
Utils::Byte::Set4Bytes(buffer, 8, localVerificationTag);
Utils::Byte::Set4Bytes(buffer, 12, remoteVerificationTag);
Utils::Byte::Set4Bytes(buffer, 16, localInitialTsn);
Utils::Byte::Set4Bytes(buffer, 20, remoteInitialTsn);
Utils::Byte::Set4Bytes(buffer, 24, remoteAdvertisedReceiverWindowCredit);
Utils::Byte::Set8Bytes(buffer, 28, tieTag);
auto* negotiatedCapabilitiesField = reinterpret_cast<NegotiatedCapabilitiesField*>(
buffer + StateCookie::NegotiatedCapabilitiesOffset);
negotiatedCapabilitiesField->reserved = 0;
negotiatedCapabilitiesField->bitA = negotiatedCapabilities.partialReliability;
negotiatedCapabilitiesField->bitB = negotiatedCapabilities.messageInterleaving;
negotiatedCapabilitiesField->bitC = negotiatedCapabilities.reConfig;
negotiatedCapabilitiesField->bitD = negotiatedCapabilities.zeroChecksum;
negotiatedCapabilitiesField->magic2 = htons(StateCookie::Magic2);
negotiatedCapabilitiesField->maxOutboundStreams =
htons(negotiatedCapabilities.maxOutboundStreams);
negotiatedCapabilitiesField->maxInboundStreams =
htons(negotiatedCapabilities.maxInboundStreams);
}
Types::SctpImplementation StateCookie::DetermineSctpImplementation(
const uint8_t* buffer, size_t bufferLength)
{
MS_TRACE();
if (bufferLength < StateCookie::Magic1Length)
{
return Types::SctpImplementation::UNKNOWN;
}
const std::string_view magic1(reinterpret_cast<const char*>(buffer), StateCookie::Magic1Length);
if (magic1 == "msworker")
{
return Types::SctpImplementation::MEDIASOUP;
}
else if (magic1 == "dcSCTP00")
{
return Types::SctpImplementation::DCSCTP;
}
else if (magic1 == "KAME-BSD")
{
return Types::SctpImplementation::USRSCTP;
}
else
{
return Types::SctpImplementation::UNKNOWN;
}
}
StateCookie::StateCookie(uint8_t* buffer, size_t bufferLength)
: Serializable(buffer, bufferLength)
{
MS_TRACE();
SetLength(StateCookie::StateCookieLength);
}
StateCookie::~StateCookie()
{
MS_TRACE();
}
void StateCookie::Dump(int indentation) const
{
MS_TRACE();
auto negotiatedCapabilities = GetNegotiatedCapabilities();
MS_DUMP_CLEAN(indentation, "<SCTP::StateCookie>");
MS_DUMP_CLEAN(indentation, " length: %zu (buffer length: %zu)", GetLength(), GetBufferLength());
MS_DUMP_CLEAN(indentation, " local verification tag: %" PRIu32, GetLocalVerificationTag());
MS_DUMP_CLEAN(indentation, " remote verification tag: %" PRIu32, GetRemoteVerificationTag());
MS_DUMP_CLEAN(indentation, " local initial tsn: %" PRIu32, GetLocalInitialTsn());
MS_DUMP_CLEAN(indentation, " remote initial tsn: %" PRIu32, GetRemoteInitialTsn());
MS_DUMP_CLEAN(
indentation,
" remote advertised receiver window credit: %" PRIu32,
GetRemoteAdvertisedReceiverWindowCredit());
MS_DUMP_CLEAN(indentation, " tie-tag: %" PRIu64, GetTieTag());
negotiatedCapabilities.Dump(indentation + 1);
MS_DUMP_CLEAN(indentation, "</SCTP::StateCookie>");
}
StateCookie* StateCookie::Clone(uint8_t* buffer, size_t bufferLength) const
{
MS_TRACE();
auto* clonedStateCookie = new StateCookie(buffer, bufferLength);
Serializable::CloneInto(clonedStateCookie);
return clonedStateCookie;
}
NegotiatedCapabilities StateCookie::GetNegotiatedCapabilities() const
{
MS_TRACE();
auto* negotiatedCapabilitiesField = GetNegotiatedCapabilitiesField();
NegotiatedCapabilities negotiatedCapabilities;
negotiatedCapabilities.maxOutboundStreams =
ntohs(negotiatedCapabilitiesField->maxOutboundStreams);
negotiatedCapabilities.maxInboundStreams =
ntohs(negotiatedCapabilitiesField->maxInboundStreams);
negotiatedCapabilities.partialReliability = negotiatedCapabilitiesField->bitA;
negotiatedCapabilities.messageInterleaving = negotiatedCapabilitiesField->bitB;
negotiatedCapabilities.reConfig = negotiatedCapabilitiesField->bitC;
negotiatedCapabilities.zeroChecksum = negotiatedCapabilitiesField->bitD;
return negotiatedCapabilities;
}
} }