Added accessor and Parse function.
Create function merged into one. BUG=webrtc:5260 Review URL: https://codereview.webrtc.org/1439553003 Cr-Commit-Position: refs/heads/master@{#11581}
This commit is contained in:
@ -10,22 +10,14 @@
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
|
||||
|
||||
using webrtc::RTCPUtility::PT_SDES;
|
||||
using webrtc::RTCPUtility::RtcpCommonHeader;
|
||||
|
||||
namespace webrtc {
|
||||
namespace rtcp {
|
||||
namespace {
|
||||
void AssignUWord8(uint8_t* buffer, size_t* offset, uint8_t value) {
|
||||
buffer[(*offset)++] = value;
|
||||
}
|
||||
|
||||
void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
|
||||
ByteWriter<uint32_t>::WriteBigEndian(buffer + *offset, value);
|
||||
*offset += 4;
|
||||
}
|
||||
// Source Description (SDES) (RFC 3550).
|
||||
//
|
||||
// 0 1 2 3
|
||||
@ -51,64 +43,144 @@ void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | CNAME=1 | length | user and domain name ...
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
const uint8_t kSdesItemType = 1;
|
||||
for (std::vector<Sdes::Chunk>::const_iterator it = chunks.begin();
|
||||
it != chunks.end(); ++it) {
|
||||
AssignUWord32(buffer, pos, (*it).ssrc);
|
||||
AssignUWord8(buffer, pos, kSdesItemType);
|
||||
AssignUWord8(buffer, pos, (*it).name.length());
|
||||
memcpy(buffer + *pos, (*it).name.data(), (*it).name.length());
|
||||
*pos += (*it).name.length();
|
||||
memset(buffer + *pos, 0, (*it).null_octets);
|
||||
*pos += (*it).null_octets;
|
||||
}
|
||||
namespace {
|
||||
const uint8_t kTerminatorTag = 0;
|
||||
const uint8_t kCnameTag = 1;
|
||||
|
||||
size_t ChunkSize(const Sdes::Chunk& chunk) {
|
||||
// Chunk:
|
||||
// SSRC/CSRC (4 bytes) | CNAME=1 (1 byte) | length (1 byte) | cname | padding.
|
||||
size_t chunk_payload_size = 4 + 1 + 1 + chunk.cname.size();
|
||||
size_t padding_size = 4 - (chunk_payload_size % 4); // Minimum 1.
|
||||
return chunk_payload_size + padding_size;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Sdes::Sdes() : block_length_(RtcpPacket::kHeaderLength) {}
|
||||
|
||||
Sdes::~Sdes() {}
|
||||
|
||||
bool Sdes::Parse(const RtcpCommonHeader& header, const uint8_t* payload) {
|
||||
RTC_CHECK(header.packet_type == kPacketType);
|
||||
|
||||
uint8_t number_of_chunks = header.count_or_format;
|
||||
std::vector<Chunk> chunks; // Read chunk into temporary array, so that in
|
||||
// case of an error original array would stay
|
||||
// unchanged.
|
||||
size_t block_length = kHeaderLength;
|
||||
|
||||
if (header.payload_size_bytes % 4 != 0) {
|
||||
LOG(LS_WARNING) << "Invalid payload size " << header.payload_size_bytes
|
||||
<< " bytes for a valid Sdes packet. Size should be"
|
||||
" multiple of 4 bytes";
|
||||
}
|
||||
const uint8_t* const payload_end = payload + header.payload_size_bytes;
|
||||
const uint8_t* looking_at = payload;
|
||||
chunks.resize(number_of_chunks);
|
||||
for (size_t i = 0; i < number_of_chunks;) {
|
||||
// Each chunk consumes at least 8 bytes.
|
||||
if (payload_end - looking_at < 8) {
|
||||
LOG(LS_WARNING) << "Not enough space left for chunk #" << (i + 1);
|
||||
return false;
|
||||
}
|
||||
chunks[i].ssrc = ByteReader<uint32_t>::ReadBigEndian(looking_at);
|
||||
looking_at += sizeof(uint32_t);
|
||||
bool cname_found = false;
|
||||
|
||||
uint8_t item_type;
|
||||
while ((item_type = *(looking_at++)) != kTerminatorTag) {
|
||||
if (looking_at >= payload_end) {
|
||||
LOG(LS_WARNING) << "Unexpected end of packet while reading chunk #"
|
||||
<< (i + 1) << ". Expected to find size of the text.";
|
||||
return false;
|
||||
}
|
||||
uint8_t item_length = *(looking_at++);
|
||||
const size_t kTerminatorSize = 1;
|
||||
if (looking_at + item_length + kTerminatorSize > payload_end) {
|
||||
LOG(LS_WARNING) << "Unexpected end of packet while reading chunk #"
|
||||
<< (i + 1) << ". Expected to find text of size "
|
||||
<< item_length;
|
||||
return false;
|
||||
}
|
||||
if (item_type == kCnameTag) {
|
||||
if (cname_found) {
|
||||
LOG(LS_WARNING) << "Found extra CNAME for same ssrc in chunk #"
|
||||
<< (i + 1);
|
||||
return false;
|
||||
}
|
||||
cname_found = true;
|
||||
chunks[i].cname.assign(reinterpret_cast<const char*>(looking_at),
|
||||
item_length);
|
||||
}
|
||||
looking_at += item_length;
|
||||
}
|
||||
if (cname_found) {
|
||||
// block_length calculates length of the packet that would be generated by
|
||||
// Build/Create functions. Adjust it same way WithCName function does.
|
||||
block_length += ChunkSize(chunks[i]);
|
||||
++i;
|
||||
} else {
|
||||
// RFC states CNAME item is mandatory.
|
||||
// But same time it allows chunk without items.
|
||||
// So while parsing, ignore all chunks without cname,
|
||||
// but do not fail the parse.
|
||||
LOG(LS_WARNING) << "CNAME not found for ssrc " << chunks[i].ssrc;
|
||||
--number_of_chunks;
|
||||
chunks.resize(number_of_chunks);
|
||||
}
|
||||
// Adjust to 32bit boundary.
|
||||
looking_at += (payload_end - looking_at) % 4;
|
||||
}
|
||||
|
||||
chunks_ = std::move(chunks);
|
||||
block_length_ = block_length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sdes::WithCName(uint32_t ssrc, const std::string& cname) {
|
||||
RTC_DCHECK_LE(cname.length(), 0xffu);
|
||||
if (chunks_.size() >= kMaxNumberOfChunks) {
|
||||
LOG(LS_WARNING) << "Max SDES chunks reached.";
|
||||
return false;
|
||||
}
|
||||
Chunk chunk;
|
||||
chunk.ssrc = ssrc;
|
||||
chunk.cname = cname;
|
||||
chunks_.push_back(chunk);
|
||||
block_length_ += ChunkSize(chunk);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sdes::Create(uint8_t* packet,
|
||||
size_t* index,
|
||||
size_t max_length,
|
||||
RtcpPacket::PacketReadyCallback* callback) const {
|
||||
assert(!chunks_.empty());
|
||||
while (*index + BlockLength() > max_length) {
|
||||
if (!OnBufferFull(packet, index, callback))
|
||||
return false;
|
||||
}
|
||||
CreateHeader(chunks_.size(), PT_SDES, HeaderLength(), packet, index);
|
||||
CreateSdes(chunks_, packet, index);
|
||||
return true;
|
||||
}
|
||||
const size_t index_end = *index + BlockLength();
|
||||
CreateHeader(chunks_.size(), kPacketType, HeaderLength(), packet, index);
|
||||
|
||||
bool Sdes::WithCName(uint32_t ssrc, const std::string& cname) {
|
||||
assert(cname.length() <= 0xff);
|
||||
if (chunks_.size() >= kMaxNumberOfChunks) {
|
||||
LOG(LS_WARNING) << "Max SDES chunks reached.";
|
||||
return false;
|
||||
for (const Sdes::Chunk& chunk : chunks_) {
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], chunk.ssrc);
|
||||
ByteWriter<uint8_t>::WriteBigEndian(&packet[*index + 4], kCnameTag);
|
||||
ByteWriter<uint8_t>::WriteBigEndian(&packet[*index + 5],
|
||||
chunk.cname.size());
|
||||
memcpy(&packet[*index + 6], chunk.cname.data(), chunk.cname.size());
|
||||
*index += (6 + chunk.cname.size());
|
||||
|
||||
// In each chunk, the list of items must be terminated by one or more null
|
||||
// octets. The next chunk must start on a 32-bit boundary.
|
||||
// CNAME (1 byte) | length (1 byte) | name | padding.
|
||||
size_t padding_size = 4 - ((6 + chunk.cname.size()) % 4);
|
||||
const int kPadding = 0;
|
||||
memset(packet + *index, kPadding, padding_size);
|
||||
*index += padding_size;
|
||||
}
|
||||
// In each chunk, the list of items must be terminated by one or more null
|
||||
// octets. The next chunk must start on a 32-bit boundary.
|
||||
// CNAME (1 byte) | length (1 byte) | name | padding.
|
||||
int null_octets = 4 - ((2 + cname.length()) % 4);
|
||||
Chunk chunk;
|
||||
chunk.ssrc = ssrc;
|
||||
chunk.name = cname;
|
||||
chunk.null_octets = null_octets;
|
||||
chunks_.push_back(chunk);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Sdes::BlockLength() const {
|
||||
// Header (4 bytes).
|
||||
// Chunk:
|
||||
// SSRC/CSRC (4 bytes) | CNAME (1 byte) | length (1 byte) | name | padding.
|
||||
size_t length = kHeaderLength;
|
||||
for (const Chunk& chunk : chunks_)
|
||||
length += 6 + chunk.name.length() + chunk.null_octets;
|
||||
assert(length % 4 == 0);
|
||||
return length;
|
||||
RTC_CHECK_EQ(*index, index_end);
|
||||
return true;
|
||||
}
|
||||
} // namespace rtcp
|
||||
} // namespace webrtc
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_
|
||||
@ -24,17 +23,24 @@ namespace rtcp {
|
||||
// Source Description (SDES) (RFC 3550).
|
||||
class Sdes : public RtcpPacket {
|
||||
public:
|
||||
Sdes() : RtcpPacket() {}
|
||||
struct Chunk {
|
||||
uint32_t ssrc;
|
||||
std::string cname;
|
||||
};
|
||||
static const uint8_t kPacketType = 202;
|
||||
|
||||
virtual ~Sdes() {}
|
||||
Sdes();
|
||||
~Sdes() override;
|
||||
|
||||
// Parse assumes header is already parsed and validated.
|
||||
bool Parse(const RTCPUtility::RtcpCommonHeader& header,
|
||||
const uint8_t* payload); // Size of the payload is in the header.
|
||||
|
||||
bool WithCName(uint32_t ssrc, const std::string& cname);
|
||||
|
||||
struct Chunk {
|
||||
uint32_t ssrc;
|
||||
std::string name;
|
||||
int null_octets;
|
||||
};
|
||||
const std::vector<Chunk>& chunks() const { return chunks_; }
|
||||
|
||||
size_t BlockLength() const override { return block_length_; }
|
||||
|
||||
protected:
|
||||
bool Create(uint8_t* packet,
|
||||
@ -43,11 +49,10 @@ class Sdes : public RtcpPacket {
|
||||
RtcpPacket::PacketReadyCallback* callback) const override;
|
||||
|
||||
private:
|
||||
static const int kMaxNumberOfChunks = 0x1f;
|
||||
|
||||
size_t BlockLength() const;
|
||||
static const size_t kMaxNumberOfChunks = 0x1f;
|
||||
|
||||
std::vector<Chunk> chunks_;
|
||||
size_t block_length_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(Sdes);
|
||||
};
|
||||
|
||||
@ -12,51 +12,77 @@
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "webrtc/test/rtcp_packet_parser.h"
|
||||
|
||||
using webrtc::rtcp::RawPacket;
|
||||
using webrtc::rtcp::Sdes;
|
||||
using webrtc::test::RtcpPacketParser;
|
||||
using webrtc::RTCPUtility::RtcpCommonHeader;
|
||||
using webrtc::RTCPUtility::RtcpParseCommonHeader;
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
const uint32_t kSenderSsrc = 0x12345678;
|
||||
const uint8_t kPadding = 0;
|
||||
const uint8_t kTerminatorTag = 0;
|
||||
const uint8_t kCnameTag = 1;
|
||||
const uint8_t kNameTag = 2;
|
||||
const uint8_t kEmailTag = 3;
|
||||
|
||||
bool Parse(const uint8_t* buffer, size_t length, Sdes* sdes) {
|
||||
RtcpCommonHeader header;
|
||||
EXPECT_TRUE(RtcpParseCommonHeader(buffer, length, &header));
|
||||
// Check that there is exactly one RTCP packet in the buffer.
|
||||
EXPECT_EQ(length, header.BlockSize());
|
||||
return sdes->Parse(header, buffer + RtcpCommonHeader::kHeaderSizeBytes);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(RtcpPacketSdesTest, WithoutChunks) {
|
||||
Sdes sdes;
|
||||
|
||||
rtc::scoped_ptr<RawPacket> packet = sdes.Build();
|
||||
Sdes parsed;
|
||||
EXPECT_TRUE(Parse(packet->Buffer(), packet->Length(), &parsed));
|
||||
|
||||
EXPECT_EQ(0u, parsed.chunks().size());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, WithOneChunk) {
|
||||
Sdes sdes;
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc, "alice@host"));
|
||||
const std::string kCname = "alice@host";
|
||||
|
||||
rtc::scoped_ptr<RawPacket> packet(sdes.Build());
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet->Buffer(), packet->Length());
|
||||
EXPECT_EQ(1, parser.sdes()->num_packets());
|
||||
EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
|
||||
EXPECT_EQ("alice@host", parser.sdes_chunk()->Cname());
|
||||
Sdes sdes;
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc, kCname));
|
||||
|
||||
rtc::scoped_ptr<RawPacket> packet = sdes.Build();
|
||||
Sdes sdes_parsed;
|
||||
Parse(packet->Buffer(), packet->Length(), &sdes_parsed);
|
||||
const Sdes& parsed = sdes_parsed; // Ensure accessors are const.
|
||||
|
||||
EXPECT_EQ(1u, parsed.chunks().size());
|
||||
EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc);
|
||||
EXPECT_EQ(kCname, parsed.chunks()[0].cname);
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, WithMultipleChunks) {
|
||||
Sdes sdes;
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc, "a"));
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 0, "a"));
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 1, "ab"));
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 2, "abc"));
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 3, "abcd"));
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 4, "abcde"));
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 5, "abcdef"));
|
||||
|
||||
rtc::scoped_ptr<RawPacket> packet(sdes.Build());
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet->Buffer(), packet->Length());
|
||||
EXPECT_EQ(1, parser.sdes()->num_packets());
|
||||
EXPECT_EQ(6, parser.sdes_chunk()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc + 5, parser.sdes_chunk()->Ssrc());
|
||||
EXPECT_EQ("abcdef", parser.sdes_chunk()->Cname());
|
||||
rtc::scoped_ptr<RawPacket> packet = sdes.Build();
|
||||
Sdes parsed;
|
||||
Parse(packet->Buffer(), packet->Length(), &parsed);
|
||||
|
||||
EXPECT_EQ(6u, parsed.chunks().size());
|
||||
EXPECT_EQ(kSenderSsrc + 5, parsed.chunks()[5].ssrc);
|
||||
EXPECT_EQ("abcdef", parsed.chunks()[5].cname);
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, WithTooManyChunks) {
|
||||
const size_t kMaxChunks = (1 << 5) - 1;
|
||||
Sdes sdes;
|
||||
const int kMaxChunks = (1 << 5) - 1;
|
||||
for (int i = 0; i < kMaxChunks; ++i) {
|
||||
for (size_t i = 0; i < kMaxChunks; ++i) {
|
||||
uint32_t ssrc = kSenderSsrc + i;
|
||||
std::ostringstream oss;
|
||||
oss << "cname" << i;
|
||||
@ -69,13 +95,165 @@ TEST(RtcpPacketSdesTest, CnameItemWithEmptyString) {
|
||||
Sdes sdes;
|
||||
EXPECT_TRUE(sdes.WithCName(kSenderSsrc, ""));
|
||||
|
||||
rtc::scoped_ptr<RawPacket> packet(sdes.Build());
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet->Buffer(), packet->Length());
|
||||
EXPECT_EQ(1, parser.sdes()->num_packets());
|
||||
EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
|
||||
EXPECT_EQ("", parser.sdes_chunk()->Cname());
|
||||
rtc::scoped_ptr<RawPacket> packet = sdes.Build();
|
||||
Sdes parsed;
|
||||
Parse(packet->Buffer(), packet->Length(), &parsed);
|
||||
|
||||
EXPECT_EQ(1u, parsed.chunks().size());
|
||||
EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc);
|
||||
EXPECT_EQ("", parsed.chunks()[0].cname);
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, ParseSkipsNonCNameField) {
|
||||
const char kName[] = "abc";
|
||||
const std::string kCname = "de";
|
||||
const uint8_t kValidPacket[] = {0x81, 202, 0x00, 0x04,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
kNameTag, 3, kName[0], kName[1], kName[2],
|
||||
kCnameTag, 2, kCname[0], kCname[1],
|
||||
kTerminatorTag, kPadding, kPadding};
|
||||
// Sanity checks packet was assembled correctly.
|
||||
ASSERT_EQ(0u, sizeof(kValidPacket) % 4);
|
||||
ASSERT_EQ(kValidPacket[3] + 1u, sizeof(kValidPacket) / 4);
|
||||
|
||||
Sdes parsed;
|
||||
EXPECT_TRUE(Parse(kValidPacket, sizeof(kValidPacket), &parsed));
|
||||
|
||||
EXPECT_EQ(1u, parsed.chunks().size());
|
||||
EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc);
|
||||
EXPECT_EQ(kCname, parsed.chunks()[0].cname);
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, ParseSkipsChunksWithoutCName) {
|
||||
const char kName[] = "ab";
|
||||
const char kEmail[] = "de";
|
||||
const std::string kCname = "def";
|
||||
const uint8_t kPacket[] = {0x82, 202, 0x00, 0x07,
|
||||
0x12, 0x34, 0x56, 0x78, // 1st chunk.
|
||||
kNameTag, 3, kName[0], kName[1], kName[2],
|
||||
kEmailTag, 2, kEmail[0], kEmail[1],
|
||||
kTerminatorTag, kPadding, kPadding,
|
||||
0x23, 0x45, 0x67, 0x89, // 2nd chunk.
|
||||
kCnameTag, 3, kCname[0], kCname[1], kCname[2],
|
||||
kTerminatorTag, kPadding, kPadding};
|
||||
// Sanity checks packet was assembled correctly.
|
||||
ASSERT_EQ(0u, sizeof(kPacket) % 4);
|
||||
ASSERT_EQ(kPacket[3] + 1u, sizeof(kPacket) / 4);
|
||||
|
||||
Sdes parsed;
|
||||
EXPECT_TRUE(Parse(kPacket, sizeof(kPacket), &parsed));
|
||||
ASSERT_EQ(1u, parsed.chunks().size());
|
||||
EXPECT_EQ(0x23456789u, parsed.chunks()[0].ssrc);
|
||||
EXPECT_EQ(kCname, parsed.chunks()[0].cname);
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, ParseFailsWithoutChunkItemTerminator) {
|
||||
const char kName[] = "abc";
|
||||
const char kCname[] = "d";
|
||||
// No place for next chunk item.
|
||||
const uint8_t kInvalidPacket[] = {0x81, 202, 0x00, 0x03,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
kNameTag, 3, kName[0], kName[1], kName[2],
|
||||
kCnameTag, 1, kCname[0]};
|
||||
// Sanity checks packet was assembled correctly.
|
||||
ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
|
||||
ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
|
||||
|
||||
Sdes parsed;
|
||||
EXPECT_FALSE(Parse(kInvalidPacket, sizeof(kInvalidPacket), &parsed));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, ParseFailsWithDamagedChunkItem) {
|
||||
const char kName[] = "ab";
|
||||
const char kCname[] = "d";
|
||||
// Next chunk item has non-terminator type, but not the size.
|
||||
const uint8_t kInvalidPacket[] = {0x81, 202, 0x00, 0x03,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
kNameTag, 2, kName[0], kName[1],
|
||||
kCnameTag, 1, kCname[0],
|
||||
kEmailTag};
|
||||
// Sanity checks packet was assembled correctly.
|
||||
ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
|
||||
ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
|
||||
|
||||
Sdes parsed;
|
||||
EXPECT_FALSE(Parse(kInvalidPacket, sizeof(kInvalidPacket), &parsed));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, ParseFailsWithTooLongChunkItem) {
|
||||
const char kName[] = "abc";
|
||||
const char kCname[] = "d";
|
||||
// Last chunk item has length that goes beyond the buffer end.
|
||||
const uint8_t kInvalidPacket[] = {0x81, 202, 0x00, 0x03,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
kNameTag, 3, kName[0], kName[1], kName[2],
|
||||
kCnameTag, 2, kCname[0]};
|
||||
// Sanity checks packet was assembled correctly.
|
||||
ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
|
||||
ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
|
||||
|
||||
Sdes parsed;
|
||||
EXPECT_FALSE(Parse(kInvalidPacket, sizeof(kInvalidPacket), &parsed));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, ParseFailsWithTwoCNames) {
|
||||
const char kCname1[] = "a";
|
||||
const char kCname2[] = "de";
|
||||
const uint8_t kInvalidPacket[] = {0x81, 202, 0x00, 0x03,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
kCnameTag, 1, kCname1[0],
|
||||
kCnameTag, 2, kCname2[0], kCname2[1],
|
||||
kTerminatorTag};
|
||||
// Sanity checks packet was assembled correctly.
|
||||
ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
|
||||
ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
|
||||
|
||||
Sdes parsed;
|
||||
EXPECT_FALSE(Parse(kInvalidPacket, sizeof(kInvalidPacket), &parsed));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, ParseFailsWithTooLittleSpaceForNextChunk) {
|
||||
const char kCname[] = "a";
|
||||
const char kEmail[] = "de";
|
||||
// Two chunks are promised in the header, but no place for the second chunk.
|
||||
const uint8_t kInvalidPacket[] = {0x82, 202, 0x00, 0x04,
|
||||
0x12, 0x34, 0x56, 0x78, // 1st chunk.
|
||||
kCnameTag, 1, kCname[0],
|
||||
kEmailTag, 2, kEmail[0], kEmail[1],
|
||||
kTerminatorTag,
|
||||
0x23, 0x45, 0x67, 0x89}; // 2nd chunk.
|
||||
// Sanity checks packet was assembled correctly.
|
||||
ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
|
||||
ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
|
||||
|
||||
Sdes parsed;
|
||||
EXPECT_FALSE(Parse(kInvalidPacket, sizeof(kInvalidPacket), &parsed));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketSdesTest, ParsedSdesCanBeReusedForBuilding) {
|
||||
Sdes source;
|
||||
const std::string kAlice = "alice@host";
|
||||
const std::string kBob = "bob@host";
|
||||
source.WithCName(kSenderSsrc, kAlice);
|
||||
|
||||
rtc::scoped_ptr<RawPacket> packet1 = source.Build();
|
||||
Sdes middle;
|
||||
Parse(packet1->Buffer(), packet1->Length(), &middle);
|
||||
|
||||
EXPECT_EQ(source.BlockLength(), middle.BlockLength());
|
||||
|
||||
middle.WithCName(kSenderSsrc + 1, kBob);
|
||||
|
||||
rtc::scoped_ptr<RawPacket> packet2 = middle.Build();
|
||||
Sdes destination;
|
||||
Parse(packet2->Buffer(), packet2->Length(), &destination);
|
||||
|
||||
EXPECT_EQ(middle.BlockLength(), destination.BlockLength());
|
||||
|
||||
EXPECT_EQ(2u, destination.chunks().size());
|
||||
EXPECT_EQ(kSenderSsrc, destination.chunks()[0].ssrc);
|
||||
EXPECT_EQ(kAlice, destination.chunks()[0].cname);
|
||||
EXPECT_EQ(kSenderSsrc + 1, destination.chunks()[1].ssrc);
|
||||
EXPECT_EQ(kBob, destination.chunks()[1].cname);
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
Reference in New Issue
Block a user