/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mediapacket.h"
#include <cstring>
#include "ipc/EnumSerializer.h"
#include "ipc/IPCMessageUtils.h"
#include "ipc/IPCMessageUtilsSpecializations.h"
namespace IPC {
template <>
struct ParamTraits<mozilla::MediaPacket::Type>
: public ContiguousEnumSerializerInclusive<
mozilla::MediaPacket::Type, mozilla::MediaPacket::UNCLASSIFIED,
mozilla::MediaPacket::SCTP> {};
}
// namespace IPC
namespace mozilla {
void MediaPacket::Copy(
const uint8_t* data, size_t len, size_t capacity) {
if (capacity < len) {
capacity = len;
}
data_ = MakeUnique<uint8_t[]>(capacity);
len_ = len;
capacity_ = capacity;
memcpy(data_.get(), data, len);
}
MediaPacket::MediaPacket(
const MediaPacket& orig)
: sdp_level_(orig.sdp_level_), type_(orig.type_) {
Copy(orig.data_.get(), orig.len_, orig.capacity_);
}
MediaPacket MediaPacket::Clone()
const {
return MediaPacket(*this); }
void MediaPacket::Serialize(IPC::MessageWriter* aWriter)
const {
WriteParam(aWriter, len_);
WriteParam(aWriter, capacity_);
WriteParam(aWriter, encrypted_len_);
WriteParam(aWriter, sdp_level_);
WriteParam(aWriter, type_);
if (len_) {
aWriter->WriteBytes(data_.get(), len_);
}
if (encrypted_len_) {
aWriter->WriteBytes(encrypted_data_.get(), encrypted_len_);
}
}
bool MediaPacket::Deserialize(IPC::MessageReader* aReader) {
Reset();
if (!ReadParam(aReader, &len_) || !ReadParam(aReader, &capacity_) ||
!ReadParam(aReader, &encrypted_len_) ||
!ReadParam(aReader, &sdp_level_) || !ReadParam(aReader, &type_)) {
return false;
}
if (capacity_ < len_) {
return false;
}
// Kinda arbitrary, but we want some sort of ceiling here.
if ((capacity_ >
1024 *
1024) || (encrypted_len_ >
1024 *
1024)) {
return false;
}
if (capacity_) {
data_ = MakeUnique<uint8_t[]>(capacity_);
if (len_) {
if (!aReader->ReadBytesInto(data_.get(), len_)) {
return false;
}
}
}
if (encrypted_len_) {
encrypted_data_ = MakeUnique<uint8_t[]>(encrypted_len_);
if (!aReader->ReadBytesInto(encrypted_data_.get(), encrypted_len_)) {
return false;
}
}
return true;
}
static bool IsRtp(
const uint8_t* data, size_t len) {
if (len <
2)
return false;
// Check if this is a RTCP packet. Logic based on the types listed in
// media/webrtc/trunk/src/modules/rtp_rtcp/source/rtp_utility.cc
// Anything outside this range is RTP.
if ((data[
1] <
192) || (data[
1] >
207))
return true;
if (data[
1] ==
192)
// FIR
return false;
if (data[
1] ==
193)
// NACK, but could also be RTP. This makes us sad
return true;
// but it's how webrtc.org behaves.
if (data[
1] ==
194)
return true;
if (data[
1] ==
195)
// IJ.
return false;
if ((data[
1] >
195) && (data[
1] <
200))
// the > 195 is redundant
return true;
if ((data[
1] >=
200) && (data[
1] <=
207))
// SR, RR, SDES, BYE,
return false;
// APP, RTPFB, PSFB, XR
MOZ_ASSERT(
false);
// Not reached, belt and suspenders.
return true;
}
void MediaPacket::Categorize() {
SetType(MediaPacket::UNCLASSIFIED);
if (!data_ || len_ <
4) {
return;
}
if (data_[
0] >=
20 && data_[
0] <=
63) {
// DTLS per RFC 7983
SetType(MediaPacket::DTLS);
}
else if (data_[
0] >
127 && data_[
0] <
192) {
// RTP/RTCP per RFC 7983
if (IsRtp(data_.get(), len_)) {
SetType(MediaPacket::SRTP);
}
else {
SetType(MediaPacket::SRTCP);
}
}
}
}
// namespace mozilla