Add ApplyPacketOptions()
When libjingle is compied with ENABLE_EXTERNAL_AUTH the sending socket needs to update RTP header in order for the outgoing packet to be valid. The corresponding code was in chromium in content/browser/renderer_host/p2p/socket_host.cc and it was impossible to reuse it anywhere else. This CL moves this code to talk/media/base/rtputils.h/cc, so it can be used outside of chrome. BUG=crbug.com/547158 R=pthatcher@webrtc.org Review URL: https://codereview.webrtc.org/1578323002 . Cr-Commit-Position: refs/heads/master@{#11261}
This commit is contained in:
parent
20ac434010
commit
dc305db059
@ -513,6 +513,8 @@
|
||||
'media/base/screencastid.h',
|
||||
'media/base/streamparams.cc',
|
||||
'media/base/streamparams.h',
|
||||
'media/base/turnutils.cc',
|
||||
'media/base/turnutils.h',
|
||||
'media/base/videoadapter.cc',
|
||||
'media/base/videoadapter.h',
|
||||
'media/base/videocapturer.cc',
|
||||
|
||||
@ -87,6 +87,7 @@
|
||||
'media/base/streamparams_unittest.cc',
|
||||
'media/base/testutils.cc',
|
||||
'media/base/testutils.h',
|
||||
'media/base/turnutils_unittest.cc',
|
||||
'media/base/videoadapter_unittest.cc',
|
||||
'media/base/videocapturer_unittest.cc',
|
||||
'media/base/videocommon_unittest.cc',
|
||||
|
||||
@ -27,6 +27,13 @@
|
||||
|
||||
#include "talk/media/base/rtputils.h"
|
||||
|
||||
#include "talk/media/base/turnutils.h"
|
||||
// PacketTimeUpdateParams is defined in asyncpacketsocket.h.
|
||||
// TODO(sergeyu): Find more appropriate place for PacketTimeUpdateParams.
|
||||
#include "webrtc/base/asyncpacketsocket.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/messagedigest.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
static const uint8_t kRtpVersion = 2;
|
||||
@ -36,6 +43,95 @@ static const size_t kRtpSeqNumOffset = 2;
|
||||
static const size_t kRtpTimestampOffset = 4;
|
||||
static const size_t kRtpSsrcOffset = 8;
|
||||
static const size_t kRtcpPayloadTypeOffset = 1;
|
||||
static const size_t kRtpExtensionHeaderLen = 4;
|
||||
static const size_t kAbsSendTimeExtensionLen = 3;
|
||||
static const size_t kOneByteExtensionHeaderLen = 1;
|
||||
|
||||
namespace {
|
||||
|
||||
// Fake auth tag written by the sender when external authentication is enabled.
|
||||
// HMAC in packet will be compared against this value before updating packet
|
||||
// with actual HMAC value.
|
||||
static const uint8_t kFakeAuthTag[10] = {
|
||||
0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd
|
||||
};
|
||||
|
||||
void UpdateAbsSendTimeExtensionValue(uint8_t* extension_data,
|
||||
size_t length,
|
||||
uint64_t time_us) {
|
||||
// Absolute send time in RTP streams.
|
||||
//
|
||||
// The absolute send time is signaled to the receiver in-band using the
|
||||
// general mechanism for RTP header extensions [RFC5285]. The payload
|
||||
// of this extension (the transmitted value) is a 24-bit unsigned integer
|
||||
// containing the sender's current time in seconds as a fixed point number
|
||||
// with 18 bits fractional part.
|
||||
//
|
||||
// The form of the absolute send time extension block:
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ID | len=2 | absolute send time |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
if (length != kAbsSendTimeExtensionLen) {
|
||||
RTC_NOTREACHED();
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert microseconds to a 6.18 fixed point value in seconds.
|
||||
uint32_t send_time = ((time_us << 18) / 1000000) & 0x00FFFFFF;
|
||||
extension_data[0] = static_cast<uint8_t>(send_time >> 16);
|
||||
extension_data[1] = static_cast<uint8_t>(send_time >> 8);
|
||||
extension_data[2] = static_cast<uint8_t>(send_time);
|
||||
}
|
||||
|
||||
// Assumes |length| is actual packet length + tag length. Updates HMAC at end of
|
||||
// the RTP packet.
|
||||
void UpdateRtpAuthTag(uint8_t* rtp,
|
||||
size_t length,
|
||||
const rtc::PacketTimeUpdateParams& packet_time_params) {
|
||||
// If there is no key, return.
|
||||
if (packet_time_params.srtp_auth_key.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t tag_length = packet_time_params.srtp_auth_tag_len;
|
||||
|
||||
// ROC (rollover counter) is at the beginning of the auth tag.
|
||||
const size_t kRocLength = 4;
|
||||
if (tag_length < kRocLength || tag_length > length) {
|
||||
RTC_NOTREACHED();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* auth_tag = rtp + (length - tag_length);
|
||||
|
||||
// We should have a fake HMAC value @ auth_tag.
|
||||
RTC_DCHECK_EQ(0, memcmp(auth_tag, kFakeAuthTag, tag_length));
|
||||
|
||||
// Copy ROC after end of rtp packet.
|
||||
memcpy(auth_tag, &packet_time_params.srtp_packet_index, kRocLength);
|
||||
// Authentication of a RTP packet will have RTP packet + ROC size.
|
||||
size_t auth_required_length = length - tag_length + kRocLength;
|
||||
|
||||
uint8_t output[64];
|
||||
size_t result = rtc::ComputeHmac(
|
||||
rtc::DIGEST_SHA_1, &packet_time_params.srtp_auth_key[0],
|
||||
packet_time_params.srtp_auth_key.size(), rtp,
|
||||
auth_required_length, output, sizeof(output));
|
||||
|
||||
if (result < tag_length) {
|
||||
RTC_NOTREACHED();
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy HMAC from output to packet. This is required as auth tag length
|
||||
// may not be equal to the actual HMAC length.
|
||||
memcpy(auth_tag, output, tag_length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool GetUint8(const void* data, size_t offset, int* value) {
|
||||
if (!data || !value) {
|
||||
@ -200,4 +296,186 @@ bool IsValidRtpPayloadType(int payload_type) {
|
||||
return payload_type >= 0 && payload_type <= 127;
|
||||
}
|
||||
|
||||
bool ValidateRtpHeader(const uint8_t* rtp,
|
||||
size_t length,
|
||||
size_t* header_length) {
|
||||
if (header_length) {
|
||||
*header_length = 0;
|
||||
}
|
||||
|
||||
if (length < kMinRtpPacketLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t cc_count = rtp[0] & 0x0F;
|
||||
size_t header_length_without_extension = kMinRtpPacketLen + 4 * cc_count;
|
||||
if (header_length_without_extension > length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If extension bit is not set, we are done with header processing, as input
|
||||
// length is verified above.
|
||||
if (!(rtp[0] & 0x10)) {
|
||||
if (header_length)
|
||||
*header_length = header_length_without_extension;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
rtp += header_length_without_extension;
|
||||
|
||||
if (header_length_without_extension + kRtpExtensionHeaderLen > length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Getting extension profile length.
|
||||
// Length is in 32 bit words.
|
||||
uint16_t extension_length_in_32bits = rtc::GetBE16(rtp + 2);
|
||||
size_t extension_length = extension_length_in_32bits * 4;
|
||||
|
||||
size_t rtp_header_length = extension_length +
|
||||
header_length_without_extension +
|
||||
kRtpExtensionHeaderLen;
|
||||
|
||||
// Verify input length against total header size.
|
||||
if (rtp_header_length > length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header_length) {
|
||||
*header_length = rtp_header_length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ValidateRtpHeader() must be called before this method to make sure, we have
|
||||
// a sane rtp packet.
|
||||
bool UpdateRtpAbsSendTimeExtension(uint8_t* rtp,
|
||||
size_t length,
|
||||
int extension_id,
|
||||
uint64_t time_us) {
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |V=2|P|X| CC |M| PT | sequence number |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | timestamp |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | synchronization source (SSRC) identifier |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | contributing source (CSRC) identifiers |
|
||||
// | .... |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
// Return if extension bit is not set.
|
||||
if (!(rtp[0] & 0x10)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t cc_count = rtp[0] & 0x0F;
|
||||
size_t header_length_without_extension = kMinRtpPacketLen + 4 * cc_count;
|
||||
|
||||
rtp += header_length_without_extension;
|
||||
|
||||
// Getting extension profile ID and length.
|
||||
uint16_t profile_id = rtc::GetBE16(rtp);
|
||||
// Length is in 32 bit words.
|
||||
uint16_t extension_length_in_32bits = rtc::GetBE16(rtp + 2);
|
||||
size_t extension_length = extension_length_in_32bits * 4;
|
||||
|
||||
rtp += kRtpExtensionHeaderLen; // Moving past extension header.
|
||||
|
||||
bool found = false;
|
||||
// WebRTC is using one byte header extension.
|
||||
// TODO(mallinath) - Handle two byte header extension.
|
||||
if (profile_id == 0xBEDE) { // OneByte extension header
|
||||
// 0
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// | ID |length |
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | 0xBE | 0xDE | length=3 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ID | L=0 | data | ID | L=1 | data...
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// ...data | 0 (pad) | 0 (pad) | ID | L=3 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | data |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
const uint8_t* extension_start = rtp;
|
||||
const uint8_t* extension_end = extension_start + extension_length;
|
||||
|
||||
while (rtp < extension_end) {
|
||||
const int id = (*rtp & 0xF0) >> 4;
|
||||
const size_t length = (*rtp & 0x0F) + 1;
|
||||
if (rtp + kOneByteExtensionHeaderLen + length > extension_end) {
|
||||
return false;
|
||||
}
|
||||
// The 4-bit length is the number minus one of data bytes of this header
|
||||
// extension element following the one-byte header.
|
||||
if (id == extension_id) {
|
||||
UpdateAbsSendTimeExtensionValue(rtp + kOneByteExtensionHeaderLen,
|
||||
length, time_us);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
rtp += kOneByteExtensionHeaderLen + length;
|
||||
// Counting padding bytes.
|
||||
while ((rtp < extension_end) && (*rtp == 0)) {
|
||||
++rtp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool ApplyPacketOptions(uint8_t* data,
|
||||
size_t length,
|
||||
const rtc::PacketTimeUpdateParams& packet_time_params,
|
||||
uint64_t time_us) {
|
||||
RTC_DCHECK(data);
|
||||
RTC_DCHECK(length);
|
||||
|
||||
// if there is no valid |rtp_sendtime_extension_id| and |srtp_auth_key| in
|
||||
// PacketOptions, nothing to be updated in this packet.
|
||||
if (packet_time_params.rtp_sendtime_extension_id == -1 &&
|
||||
packet_time_params.srtp_auth_key.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there is a srtp auth key present then the packet must be an RTP packet.
|
||||
// RTP packet may have been wrapped in a TURN Channel Data or TURN send
|
||||
// indication.
|
||||
size_t rtp_start_pos;
|
||||
size_t rtp_length;
|
||||
if (!UnwrapTurnPacket(data, length, &rtp_start_pos, &rtp_length)) {
|
||||
RTC_NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Making sure we have a valid RTP packet at the end.
|
||||
if (!IsRtpPacket(data + rtp_start_pos, rtp_length) ||
|
||||
!ValidateRtpHeader(data + rtp_start_pos, rtp_length, nullptr)) {
|
||||
RTC_NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* start = data + rtp_start_pos;
|
||||
// If packet option has non default value (-1) for sendtime extension id,
|
||||
// then we should parse the rtp packet to update the timestamp. Otherwise
|
||||
// just calculate HMAC and update packet with it.
|
||||
if (packet_time_params.rtp_sendtime_extension_id != -1) {
|
||||
UpdateRtpAbsSendTimeExtension(start, rtp_length,
|
||||
packet_time_params.rtp_sendtime_extension_id,
|
||||
time_us);
|
||||
}
|
||||
|
||||
UpdateRtpAuthTag(start, rtp_length, packet_time_params);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
@ -30,6 +30,10 @@
|
||||
|
||||
#include "webrtc/base/byteorder.h"
|
||||
|
||||
namespace rtc {
|
||||
struct PacketTimeUpdateParams;
|
||||
} // namespace rtc
|
||||
|
||||
namespace cricket {
|
||||
|
||||
const size_t kMinRtpPacketLen = 12;
|
||||
@ -71,6 +75,25 @@ bool IsRtpPacket(const void* data, size_t len);
|
||||
// True if |payload type| is 0-127.
|
||||
bool IsValidRtpPayloadType(int payload_type);
|
||||
|
||||
// Verifies that a packet has a valid RTP header.
|
||||
bool ValidateRtpHeader(const uint8_t* rtp,
|
||||
size_t length,
|
||||
size_t* header_length);
|
||||
|
||||
// Helper method which updates the absolute send time extension if present.
|
||||
bool UpdateRtpAbsSendTimeExtension(uint8_t* rtp,
|
||||
size_t length,
|
||||
int extension_id,
|
||||
uint64_t time_us);
|
||||
|
||||
// Applies specified |options| to the packet. It updates the absolute send time
|
||||
// extension header if it is present present then updates HMAC.
|
||||
bool ApplyPacketOptions(uint8_t* data,
|
||||
size_t length,
|
||||
const rtc::PacketTimeUpdateParams& packet_time_params,
|
||||
uint64_t time_us);
|
||||
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // TALK_MEDIA_BASE_RTPUTILS_H_
|
||||
|
||||
@ -27,31 +27,32 @@
|
||||
|
||||
#include "talk/media/base/fakertp.h"
|
||||
#include "talk/media/base/rtputils.h"
|
||||
#include "webrtc/base/asyncpacketsocket.h"
|
||||
#include "webrtc/base/gunit.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
static const unsigned char kRtpPacketWithMarker[] = {
|
||||
static const uint8_t kRtpPacketWithMarker[] = {
|
||||
0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
// 3 CSRCs (0x01020304, 0x12345678, 0xAABBCCDD)
|
||||
// Extension (0xBEDE, 0x1122334455667788)
|
||||
static const unsigned char kRtpPacketWithMarkerAndCsrcAndExtension[] = {
|
||||
static const uint8_t kRtpPacketWithMarkerAndCsrcAndExtension[] = {
|
||||
0x93, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD,
|
||||
0xBE, 0xDE, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88
|
||||
};
|
||||
static const unsigned char kInvalidPacket[] = { 0x80, 0x00 };
|
||||
static const unsigned char kInvalidPacketWithCsrc[] = {
|
||||
static const uint8_t kInvalidPacket[] = { 0x80, 0x00 };
|
||||
static const uint8_t kInvalidPacketWithCsrc[] = {
|
||||
0x83, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC
|
||||
};
|
||||
static const unsigned char kInvalidPacketWithCsrcAndExtension1[] = {
|
||||
static const uint8_t kInvalidPacketWithCsrcAndExtension1[] = {
|
||||
0x93, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD,
|
||||
0xBE, 0xDE, 0x00
|
||||
};
|
||||
static const unsigned char kInvalidPacketWithCsrcAndExtension2[] = {
|
||||
static const uint8_t kInvalidPacketWithCsrcAndExtension2[] = {
|
||||
0x93, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD,
|
||||
0xBE, 0xDE, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
|
||||
@ -59,21 +60,48 @@ static const unsigned char kInvalidPacketWithCsrcAndExtension2[] = {
|
||||
|
||||
// PT = 206, FMT = 1, Sender SSRC = 0x1111, Media SSRC = 0x1111
|
||||
// No FCI information is needed for PLI.
|
||||
static const unsigned char kNonCompoundRtcpPliFeedbackPacket[] = {
|
||||
static const uint8_t kNonCompoundRtcpPliFeedbackPacket[] = {
|
||||
0x81, 0xCE, 0x00, 0x0C, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11
|
||||
};
|
||||
|
||||
// Packet has only mandatory fixed RTCP header
|
||||
// PT = 204, SSRC = 0x1111
|
||||
static const unsigned char kNonCompoundRtcpAppPacket[] = {
|
||||
static const uint8_t kNonCompoundRtcpAppPacket[] = {
|
||||
0x81, 0xCC, 0x00, 0x0C, 0x00, 0x00, 0x11, 0x11
|
||||
};
|
||||
|
||||
// PT = 202, Source count = 0
|
||||
static const unsigned char kNonCompoundRtcpSDESPacket[] = {
|
||||
static const uint8_t kNonCompoundRtcpSDESPacket[] = {
|
||||
0x80, 0xCA, 0x00, 0x00
|
||||
};
|
||||
|
||||
static uint8_t kFakeTag[4] = { 0xba, 0xdd, 0xba, 0xdd };
|
||||
static uint8_t kTestKey[] = "12345678901234567890";
|
||||
static uint8_t kTestAstValue[3] = { 0xaa, 0xbb, 0xcc };
|
||||
|
||||
// Valid rtp Message with 2 byte header extension.
|
||||
static uint8_t kRtpMsgWith2ByteExtnHeader[] = {
|
||||
0x90, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xAA, 0xBB, 0xCC, 0XDD, // SSRC
|
||||
0x10, 0x00, 0x00, 0x01, // 2 Byte header extension
|
||||
0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// RTP packet with single byte extension header of length 4 bytes.
|
||||
// Extension id = 3 and length = 3
|
||||
static uint8_t kRtpMsgWithAbsSendTimeExtension[] = {
|
||||
0x90, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xBE, 0xDE, 0x00, 0x02,
|
||||
0x22, 0x00, 0x02, 0x1c,
|
||||
0x32, 0xaa, 0xbb, 0xcc,
|
||||
};
|
||||
|
||||
// Index of AbsSendTimeExtn data in message |kRtpMsgWithAbsSendTimeExtension|.
|
||||
static const int kAstIndexInRtpMsg = 21;
|
||||
|
||||
TEST(RtpUtilsTest, GetRtp) {
|
||||
EXPECT_TRUE(IsRtpPacket(kPcmuFrame, sizeof(kPcmuFrame)));
|
||||
|
||||
@ -110,7 +138,7 @@ TEST(RtpUtilsTest, GetRtp) {
|
||||
}
|
||||
|
||||
TEST(RtpUtilsTest, SetRtpHeader) {
|
||||
unsigned char packet[] = {
|
||||
uint8_t packet[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
@ -169,4 +197,172 @@ TEST(RtpUtilsTest, GetRtcp) {
|
||||
&ssrc));
|
||||
}
|
||||
|
||||
// Invalid RTP packets.
|
||||
TEST(RtpUtilsTest, InvalidRtpHeader) {
|
||||
// Rtp message with invalid length.
|
||||
const uint8_t kRtpMsgWithInvalidLength[] = {
|
||||
0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xAA, 0xBB, 0xCC, 0XDD, // SSRC
|
||||
0xDD, 0xCC, 0xBB, 0xAA, // Only 1 CSRC, but CC count is 4.
|
||||
};
|
||||
EXPECT_FALSE(ValidateRtpHeader(kRtpMsgWithInvalidLength,
|
||||
sizeof(kRtpMsgWithInvalidLength), nullptr));
|
||||
|
||||
// Rtp message with single byte header extension, invalid extension length.
|
||||
const uint8_t kRtpMsgWithInvalidExtnLength[] = {
|
||||
0x90, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xBE, 0xDE, 0x0A, 0x00, // Extn length - 0x0A00
|
||||
};
|
||||
EXPECT_FALSE(ValidateRtpHeader(kRtpMsgWithInvalidExtnLength,
|
||||
sizeof(kRtpMsgWithInvalidExtnLength),
|
||||
nullptr));
|
||||
}
|
||||
|
||||
// Valid RTP packet with a 2byte header extension.
|
||||
TEST(RtpUtilsTest, Valid2ByteExtnHdrRtpMessage) {
|
||||
EXPECT_TRUE(ValidateRtpHeader(kRtpMsgWith2ByteExtnHeader,
|
||||
sizeof(kRtpMsgWith2ByteExtnHeader), nullptr));
|
||||
}
|
||||
|
||||
// Valid RTP packet which has 1 byte header AbsSendTime extension in it.
|
||||
TEST(RtpUtilsTest, ValidRtpPacketWithAbsSendTimeExtension) {
|
||||
EXPECT_TRUE(ValidateRtpHeader(kRtpMsgWithAbsSendTimeExtension,
|
||||
sizeof(kRtpMsgWithAbsSendTimeExtension),
|
||||
nullptr));
|
||||
}
|
||||
|
||||
// Verify handling of a 2 byte extension header RTP messsage. Currently these
|
||||
// messages are not supported.
|
||||
TEST(RtpUtilsTest, UpdateAbsSendTimeExtensionIn2ByteHeaderExtn) {
|
||||
std::vector<uint8_t> data(
|
||||
kRtpMsgWith2ByteExtnHeader,
|
||||
kRtpMsgWith2ByteExtnHeader + sizeof(kRtpMsgWith2ByteExtnHeader));
|
||||
EXPECT_FALSE(UpdateRtpAbsSendTimeExtension(&data[0], data.size(), 3, 0));
|
||||
}
|
||||
|
||||
// Verify finding an extension ID in the TURN send indication message.
|
||||
TEST(RtpUtilsTest, UpdateAbsSendTimeExtensionInTurnSendIndication) {
|
||||
// A valid STUN indication message with a valid RTP header in data attribute
|
||||
// payload field and no extension bit set.
|
||||
uint8_t message_without_extension[] = {
|
||||
0x00, 0x16, 0x00, 0x18, // length of
|
||||
0x21, 0x12, 0xA4, 0x42, // magic cookie
|
||||
'0', '1', '2', '3', // transaction id
|
||||
'4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b',
|
||||
0x00, 0x20, 0x00, 0x04, // Mapped address.
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x13, 0x00, 0x0C, // Data attribute.
|
||||
0x80, 0x00, 0x00, 0x00, // RTP packet.
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
EXPECT_TRUE(UpdateRtpAbsSendTimeExtension(
|
||||
message_without_extension, sizeof(message_without_extension), 3, 0));
|
||||
|
||||
// A valid STUN indication message with a valid RTP header and a extension
|
||||
// header.
|
||||
uint8_t message[] = {
|
||||
0x00, 0x16, 0x00, 0x24, // length of
|
||||
0x21, 0x12, 0xA4, 0x42, // magic cookie
|
||||
'0', '1', '2', '3', // transaction id
|
||||
'4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b',
|
||||
0x00, 0x20, 0x00, 0x04, // Mapped address.
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x13, 0x00, 0x18, // Data attribute.
|
||||
0x90, 0x00, 0x00, 0x00, // RTP packet.
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xDE,
|
||||
0x00, 0x02, 0x22, 0xaa, 0xbb, 0xcc, 0x32, 0xaa, 0xbb, 0xcc,
|
||||
};
|
||||
EXPECT_TRUE(UpdateRtpAbsSendTimeExtension(message, sizeof(message), 3, 0));
|
||||
}
|
||||
|
||||
// Test without any packet options variables set. This method should return
|
||||
// without HMAC value in the packet.
|
||||
TEST(RtpUtilsTest, ApplyPacketOptionsWithDefaultValues) {
|
||||
rtc::PacketTimeUpdateParams packet_time_params;
|
||||
std::vector<uint8_t> rtp_packet(kRtpMsgWithAbsSendTimeExtension,
|
||||
kRtpMsgWithAbsSendTimeExtension +
|
||||
sizeof(kRtpMsgWithAbsSendTimeExtension));
|
||||
rtp_packet.insert(rtp_packet.end(), kFakeTag, kFakeTag + sizeof(kFakeTag));
|
||||
EXPECT_TRUE(ApplyPacketOptions(&rtp_packet[0], rtp_packet.size(),
|
||||
packet_time_params, 0));
|
||||
|
||||
// Making sure HMAC wasn't updated..
|
||||
EXPECT_EQ(0, memcmp(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)],
|
||||
kFakeTag, 4));
|
||||
|
||||
// Verify AbsouluteSendTime extension field wasn't modified.
|
||||
EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg], kTestAstValue,
|
||||
sizeof(kTestAstValue)));
|
||||
}
|
||||
|
||||
// Veirfy HMAC is updated when packet option parameters are set.
|
||||
TEST(RtpUtilsTest, ApplyPacketOptionsWithAuthParams) {
|
||||
rtc::PacketTimeUpdateParams packet_time_params;
|
||||
packet_time_params.srtp_auth_key.assign(kTestKey,
|
||||
kTestKey + sizeof(kTestKey));
|
||||
packet_time_params.srtp_auth_tag_len = 4;
|
||||
|
||||
std::vector<uint8_t> rtp_packet(kRtpMsgWithAbsSendTimeExtension,
|
||||
kRtpMsgWithAbsSendTimeExtension +
|
||||
sizeof(kRtpMsgWithAbsSendTimeExtension));
|
||||
rtp_packet.insert(rtp_packet.end(), kFakeTag, kFakeTag + sizeof(kFakeTag));
|
||||
EXPECT_TRUE(ApplyPacketOptions(&rtp_packet[0], rtp_packet.size(),
|
||||
packet_time_params, 0));
|
||||
|
||||
uint8_t kExpectedTag[] = {0xc1, 0x7a, 0x8c, 0xa0};
|
||||
EXPECT_EQ(0, memcmp(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)],
|
||||
kExpectedTag, sizeof(kExpectedTag)));
|
||||
|
||||
// Verify AbsouluteSendTime extension field is not modified.
|
||||
EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg], kTestAstValue,
|
||||
sizeof(kTestAstValue)));
|
||||
}
|
||||
|
||||
// Verify finding an extension ID in a raw rtp message.
|
||||
TEST(RtpUtilsTest, UpdateAbsSendTimeExtensionInRtpPacket) {
|
||||
std::vector<uint8_t> rtp_packet(kRtpMsgWithAbsSendTimeExtension,
|
||||
kRtpMsgWithAbsSendTimeExtension +
|
||||
sizeof(kRtpMsgWithAbsSendTimeExtension));
|
||||
|
||||
EXPECT_TRUE(UpdateRtpAbsSendTimeExtension(&rtp_packet[0], rtp_packet.size(),
|
||||
3, 51183266));
|
||||
|
||||
// Verify that the timestamp was updated.
|
||||
const uint8_t kExpectedTimestamp[3] = {0xcc, 0xbb, 0xaa};
|
||||
EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg], kExpectedTimestamp,
|
||||
sizeof(kExpectedTimestamp)));
|
||||
}
|
||||
|
||||
// Verify we update both AbsSendTime extension header and HMAC.
|
||||
TEST(RtpUtilsTest, ApplyPacketOptionsWithAuthParamsAndAbsSendTime) {
|
||||
rtc::PacketTimeUpdateParams packet_time_params;
|
||||
packet_time_params.srtp_auth_key.assign(kTestKey,
|
||||
kTestKey + sizeof(kTestKey));
|
||||
packet_time_params.srtp_auth_tag_len = 4;
|
||||
packet_time_params.rtp_sendtime_extension_id = 3;
|
||||
// 3 is also present in the test message.
|
||||
|
||||
std::vector<uint8_t> rtp_packet(kRtpMsgWithAbsSendTimeExtension,
|
||||
kRtpMsgWithAbsSendTimeExtension +
|
||||
sizeof(kRtpMsgWithAbsSendTimeExtension));
|
||||
rtp_packet.insert(rtp_packet.end(), kFakeTag, kFakeTag + sizeof(kFakeTag));
|
||||
EXPECT_TRUE(ApplyPacketOptions(&rtp_packet[0], rtp_packet.size(),
|
||||
packet_time_params, 51183266));
|
||||
|
||||
const uint8_t kExpectedTag[] = {0x81, 0xd1, 0x2c, 0x0e};
|
||||
EXPECT_EQ(0, memcmp(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)],
|
||||
kExpectedTag, sizeof(kExpectedTag)));
|
||||
|
||||
// Verify that the timestamp was updated.
|
||||
const uint8_t kExpectedTimestamp[3] = {0xcc, 0xbb, 0xaa};
|
||||
EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg], kExpectedTimestamp,
|
||||
sizeof(kExpectedTimestamp)));
|
||||
}
|
||||
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
144
talk/media/base/turnutils.cc
Normal file
144
talk/media/base/turnutils.cc
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/media/base/turnutils.h"
|
||||
|
||||
#include "webrtc/base/byteorder.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/p2p/base/stun.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
namespace {
|
||||
|
||||
const size_t kTurnChannelHeaderLength = 4;
|
||||
|
||||
bool IsTurnChannelData(const uint8_t* data, size_t length) {
|
||||
return length >= kTurnChannelHeaderLength && ((*data & 0xC0) == 0x40);
|
||||
}
|
||||
|
||||
bool IsTurnSendIndicationPacket(const uint8_t* data, size_t length) {
|
||||
if (length < kStunHeaderSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t type = rtc::GetBE16(data);
|
||||
return (type == TURN_SEND_INDICATION);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool UnwrapTurnPacket(const uint8_t* packet,
|
||||
size_t packet_size,
|
||||
size_t* content_position,
|
||||
size_t* content_size) {
|
||||
if (IsTurnChannelData(packet, packet_size)) {
|
||||
// Turn Channel Message header format.
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Channel Number | Length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | |
|
||||
// / Application Data /
|
||||
// / /
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
size_t length = rtc::GetBE16(&packet[2]);
|
||||
if (length + kTurnChannelHeaderLength > packet_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*content_position = kTurnChannelHeaderLength;
|
||||
*content_size = length;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsTurnSendIndicationPacket(packet, packet_size)) {
|
||||
// Validate STUN message length.
|
||||
const size_t stun_message_length = rtc::GetBE16(&packet[2]);
|
||||
if (stun_message_length + kStunHeaderSize != packet_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// First skip mandatory stun header which is of 20 bytes.
|
||||
size_t pos = kStunHeaderSize;
|
||||
// Loop through STUN attributes until we find STUN DATA attribute.
|
||||
while (pos < packet_size) {
|
||||
// Keep reading STUN attributes until we hit DATA attribute.
|
||||
// Attribute will be a TLV structure.
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Type | Length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Value (variable) ....
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// The value in the length field MUST contain the length of the Value
|
||||
// part of the attribute, prior to padding, measured in bytes. Since
|
||||
// STUN aligns attributes on 32-bit boundaries, attributes whose content
|
||||
// is not a multiple of 4 bytes are padded with 1, 2, or 3 bytes of
|
||||
// padding so that its value contains a multiple of 4 bytes. The
|
||||
// padding bits are ignored, and may be any value.
|
||||
uint16_t attr_type, attr_length;
|
||||
const int kAttrHeaderLength = sizeof(attr_type) + sizeof(attr_length);
|
||||
|
||||
if (packet_size < pos + kAttrHeaderLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Getting attribute type and length.
|
||||
attr_type = rtc::GetBE16(&packet[pos]);
|
||||
attr_length = rtc::GetBE16(&packet[pos + sizeof(attr_type)]);
|
||||
|
||||
pos += kAttrHeaderLength; // Skip STUN_DATA_ATTR header.
|
||||
|
||||
// Checking for bogus attribute length.
|
||||
if (pos + attr_length > packet_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attr_type == STUN_ATTR_DATA) {
|
||||
*content_position = pos;
|
||||
*content_size = attr_length;
|
||||
return true;
|
||||
}
|
||||
|
||||
pos += attr_length;
|
||||
if ((attr_length % 4) != 0) {
|
||||
pos += (4 - (attr_length % 4));
|
||||
}
|
||||
}
|
||||
|
||||
// There is no data attribute present in the message.
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is not a TURN packet.
|
||||
*content_position = 0;
|
||||
*content_size = packet_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
47
talk/media/base/turnutils.h
Normal file
47
talk/media/base/turnutils.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TALK_MEDIA_BASE_TURNUTILS_H_
|
||||
#define TALK_MEDIA_BASE_TURNUTILS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace cricket {
|
||||
|
||||
struct PacketOptions;
|
||||
|
||||
// Finds data location within a TURN Channel Message or TURN Send Indication
|
||||
// message.
|
||||
bool UnwrapTurnPacket(const uint8_t* packet,
|
||||
size_t packet_size,
|
||||
size_t* content_position,
|
||||
size_t* content_size);
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // TALK_MEDIA_BASE_TURNUTILS_H_
|
||||
137
talk/media/base/turnutils_unittest.cc
Normal file
137
talk/media/base/turnutils_unittest.cc
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/media/base/turnutils.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webrtc/base/gunit.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
// Invalid TURN send indication messages. Messages are proper STUN
|
||||
// messages with incorrect values in attributes.
|
||||
TEST(TurnUtilsTest, InvalidTurnSendIndicationMessages) {
|
||||
size_t content_pos = SIZE_MAX;
|
||||
size_t content_size = SIZE_MAX;
|
||||
|
||||
// Stun Indication message with Zero length
|
||||
uint8_t kTurnSendIndicationMsgWithNoAttributes[] = {
|
||||
0x00, 0x16, 0x00, 0x00, // Zero length
|
||||
0x21, 0x12, 0xA4, 0x42, // magic cookie
|
||||
'0', '1', '2', '3', // transaction id
|
||||
'4', '5', '6', '7', '8', '9', 'a', 'b',
|
||||
};
|
||||
EXPECT_FALSE(UnwrapTurnPacket(kTurnSendIndicationMsgWithNoAttributes,
|
||||
sizeof(kTurnSendIndicationMsgWithNoAttributes),
|
||||
&content_pos, &content_size));
|
||||
EXPECT_EQ(SIZE_MAX, content_pos);
|
||||
EXPECT_EQ(SIZE_MAX, content_size);
|
||||
|
||||
// Stun Send Indication message with invalid length in stun header.
|
||||
const uint8_t kTurnSendIndicationMsgWithInvalidLength[] = {
|
||||
0x00, 0x16, 0xFF, 0x00, // length of 0xFF00
|
||||
0x21, 0x12, 0xA4, 0x42, // magic cookie
|
||||
'0', '1', '2', '3', // transaction id
|
||||
'4', '5', '6', '7', '8', '9', 'a', 'b',
|
||||
};
|
||||
EXPECT_FALSE(UnwrapTurnPacket(kTurnSendIndicationMsgWithInvalidLength,
|
||||
sizeof(kTurnSendIndicationMsgWithInvalidLength),
|
||||
&content_pos, &content_size));
|
||||
EXPECT_EQ(SIZE_MAX, content_pos);
|
||||
EXPECT_EQ(SIZE_MAX, content_size);
|
||||
|
||||
// Stun Send Indication message with no DATA attribute in message.
|
||||
const uint8_t kTurnSendIndicatinMsgWithNoDataAttribute[] = {
|
||||
0x00, 0x16, 0x00, 0x08, // length of
|
||||
0x21, 0x12, 0xA4, 0x42, // magic cookie
|
||||
'0', '1', '2', '3', // transaction id
|
||||
'4', '5', '6', '7', '8', '9', 'a', 'b',
|
||||
0x00, 0x20, 0x00, 0x04, // Mapped address.
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
EXPECT_FALSE(
|
||||
UnwrapTurnPacket(kTurnSendIndicatinMsgWithNoDataAttribute,
|
||||
sizeof(kTurnSendIndicatinMsgWithNoDataAttribute),
|
||||
&content_pos, &content_size));
|
||||
EXPECT_EQ(SIZE_MAX, content_pos);
|
||||
EXPECT_EQ(SIZE_MAX, content_size);
|
||||
}
|
||||
|
||||
// Valid TURN Send Indication messages.
|
||||
TEST(TurnUtilsTest, ValidTurnSendIndicationMessage) {
|
||||
size_t content_pos = SIZE_MAX;
|
||||
size_t content_size = SIZE_MAX;
|
||||
// A valid STUN indication message with a valid RTP header in data attribute
|
||||
// payload field and no extension bit set.
|
||||
const uint8_t kTurnSendIndicationMsgWithoutRtpExtension[] = {
|
||||
0x00, 0x16, 0x00, 0x18, // length of
|
||||
0x21, 0x12, 0xA4, 0x42, // magic cookie
|
||||
'0', '1', '2', '3', // transaction id
|
||||
'4', '5', '6', '7', '8', '9', 'a', 'b',
|
||||
0x00, 0x20, 0x00, 0x04, // Mapped address.
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x13, 0x00, 0x0C, // Data attribute.
|
||||
0x80, 0x00, 0x00, 0x00, // RTP packet.
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
EXPECT_TRUE(UnwrapTurnPacket(
|
||||
kTurnSendIndicationMsgWithoutRtpExtension,
|
||||
sizeof(kTurnSendIndicationMsgWithoutRtpExtension), &content_pos,
|
||||
&content_size));
|
||||
EXPECT_EQ(12U, content_size);
|
||||
EXPECT_EQ(32U, content_pos);
|
||||
}
|
||||
|
||||
// Verify that parsing of valid TURN Channel Messages.
|
||||
TEST(TurnUtilsTest, ValidTurnChannelMessages) {
|
||||
const uint8_t kTurnChannelMsgWithRtpPacket[] = {
|
||||
0x40, 0x00, 0x00, 0x0C,
|
||||
0x80, 0x00, 0x00, 0x00, // RTP packet.
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
size_t content_pos = 0, content_size = 0;
|
||||
EXPECT_TRUE(UnwrapTurnPacket(
|
||||
kTurnChannelMsgWithRtpPacket,
|
||||
sizeof(kTurnChannelMsgWithRtpPacket), &content_pos, &content_size));
|
||||
EXPECT_EQ(12U, content_size);
|
||||
EXPECT_EQ(4U, content_pos);
|
||||
}
|
||||
|
||||
TEST(TurnUtilsTest, ChannelMessageZeroLength) {
|
||||
const uint8_t kTurnChannelMsgWithZeroLength[] = {0x40, 0x00, 0x00, 0x00};
|
||||
size_t content_pos = SIZE_MAX;
|
||||
size_t content_size = SIZE_MAX;
|
||||
EXPECT_TRUE(UnwrapTurnPacket(kTurnChannelMsgWithZeroLength,
|
||||
sizeof(kTurnChannelMsgWithZeroLength),
|
||||
&content_pos, &content_size));
|
||||
EXPECT_EQ(4, content_pos);
|
||||
EXPECT_EQ(0, content_size);
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
Loading…
x
Reference in New Issue
Block a user