Bug 1455647 - Part 3: Move SRTP into a TransportLayer. r=drno

MozReview-Commit-ID: LWZFPVDYZKb

--HG--
rename : media/webrtc/signaling/src/mediapipeline/SrtpFlow.cpp => media/mtransport/SrtpFlow.cpp
rename : media/webrtc/signaling/src/mediapipeline/SrtpFlow.h => media/mtransport/SrtpFlow.h
extra : rebase_source : 16e1e38c0c6f9153375735b7cb93a8286364df5f
This commit is contained in:
Byron Campen [:bwc] 2018-04-23 13:14:30 -05:00
Родитель ab2913f71d
Коммит 148a322296
13 изменённых файлов: 411 добавлений и 281 удалений

Просмотреть файл

@ -13,16 +13,11 @@
#include "mozilla/RefPtr.h"
static const char* sfLogTag = "SrtpFlow";
#ifdef LOGTAG
#undef LOGTAG
#endif
#define LOGTAG sfLogTag
using namespace mozilla;
namespace mozilla {
MOZ_MTLOG_MODULE("mtransport")
bool SrtpFlow::initialized; // Static
SrtpFlow::~SrtpFlow() {
@ -42,12 +37,12 @@ RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite,
RefPtr<SrtpFlow> flow = new SrtpFlow();
if (!key) {
CSFLogError(LOGTAG, "Null SRTP key specified");
MOZ_MTLOG(ML_ERROR, "Null SRTP key specified");
return nullptr;
}
if (key_len != SRTP_TOTAL_KEY_LENGTH) {
CSFLogError(LOGTAG, "Invalid SRTP key length");
MOZ_MTLOG(ML_ERROR, "Invalid SRTP key length");
return nullptr;
}
@ -58,19 +53,19 @@ RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite,
// since any flow can only have one cipher suite with DTLS-SRTP
switch (cipher_suite) {
case SRTP_AES128_CM_HMAC_SHA1_80:
CSFLogDebug(LOGTAG,
MOZ_MTLOG(ML_DEBUG,
"Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_80");
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
break;
case SRTP_AES128_CM_HMAC_SHA1_32:
CSFLogDebug(LOGTAG,
MOZ_MTLOG(ML_DEBUG,
"Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_32");
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // 80-bit per RFC 5764
break; // S 4.1.2.
default:
CSFLogError(LOGTAG, "Request to set unknown SRTP cipher suite");
MOZ_MTLOG(ML_ERROR, "Request to set unknown SRTP cipher suite");
return nullptr;
}
// This key is copied into the srtp_t object, so we don't
@ -87,7 +82,7 @@ RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite,
// Now make the session
srtp_err_status_t r = srtp_create(&flow->session_, &policy);
if (r != srtp_err_status_ok) {
CSFLogError(LOGTAG, "Error creating srtp session");
MOZ_MTLOG(ML_ERROR, "Error creating srtp session");
return nullptr;
}
@ -99,30 +94,30 @@ nsresult SrtpFlow::CheckInputs(bool protect, void *in, int in_len,
int max_len, int *out_len) {
MOZ_ASSERT(in);
if (!in) {
CSFLogError(LOGTAG, "NULL input value");
MOZ_MTLOG(ML_ERROR, "NULL input value");
return NS_ERROR_NULL_POINTER;
}
if (in_len < 0) {
CSFLogError(LOGTAG, "Input length is negative");
MOZ_MTLOG(ML_ERROR, "Input length is negative");
return NS_ERROR_ILLEGAL_VALUE;
}
if (max_len < 0) {
CSFLogError(LOGTAG, "Max output length is negative");
MOZ_MTLOG(ML_ERROR, "Max output length is negative");
return NS_ERROR_ILLEGAL_VALUE;
}
if (protect) {
if ((max_len < SRTP_MAX_EXPANSION) ||
((max_len - SRTP_MAX_EXPANSION) < in_len)) {
CSFLogError(LOGTAG, "Output too short");
MOZ_MTLOG(ML_ERROR, "Output too short");
return NS_ERROR_ILLEGAL_VALUE;
}
}
else {
if (in_len > max_len) {
CSFLogError(LOGTAG, "Output too short");
MOZ_MTLOG(ML_ERROR, "Output too short");
return NS_ERROR_ILLEGAL_VALUE;
}
}
@ -140,7 +135,7 @@ nsresult SrtpFlow::ProtectRtp(void *in, int in_len,
srtp_err_status_t r = srtp_protect(session_, in, &len);
if (r != srtp_err_status_ok) {
CSFLogError(LOGTAG, "Error protecting SRTP packet");
MOZ_MTLOG(ML_ERROR, "Error protecting SRTP packet");
return NS_ERROR_FAILURE;
}
@ -148,8 +143,8 @@ nsresult SrtpFlow::ProtectRtp(void *in, int in_len,
*out_len = len;
CSFLogDebug(LOGTAG, "Successfully protected an SRTP packet of len %d",
*out_len);
MOZ_MTLOG(ML_DEBUG, "Successfully protected an SRTP packet of len "
<< *out_len);
return NS_OK;
}
@ -164,15 +159,15 @@ nsresult SrtpFlow::UnprotectRtp(void *in, int in_len,
srtp_err_status_t r = srtp_unprotect(session_, in, &len);
if (r != srtp_err_status_ok) {
CSFLogError(LOGTAG, "Error unprotecting SRTP packet error=%d", (int)r);
MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTP packet error=" << (int)r);
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(len <= max_len);
*out_len = len;
CSFLogDebug(LOGTAG, "Successfully unprotected an SRTP packet of len %d",
*out_len);
MOZ_MTLOG(ML_DEBUG, "Successfully unprotected an SRTP packet of len "
<< *out_len);
return NS_OK;
}
@ -187,15 +182,15 @@ nsresult SrtpFlow::ProtectRtcp(void *in, int in_len,
srtp_err_status_t r = srtp_protect_rtcp(session_, in, &len);
if (r != srtp_err_status_ok) {
CSFLogError(LOGTAG, "Error protecting SRTCP packet");
MOZ_MTLOG(ML_ERROR, "Error protecting SRTCP packet");
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(len <= max_len);
*out_len = len;
CSFLogDebug(LOGTAG, "Successfully protected an SRTCP packet of len %d",
*out_len);
MOZ_MTLOG(ML_DEBUG, "Successfully protected an SRTCP packet of len "
<< *out_len);
return NS_OK;
}
@ -210,15 +205,15 @@ nsresult SrtpFlow::UnprotectRtcp(void *in, int in_len,
srtp_err_status_t r = srtp_unprotect_rtcp(session_, in, &len);
if (r != srtp_err_status_ok) {
CSFLogError(LOGTAG, "Error unprotecting SRTCP packet error=%d", (int)r);
MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTCP packet error=" << (int)r);
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(len <= max_len);
*out_len = len;
CSFLogDebug(LOGTAG, "Successfully unprotected an SRTCP packet of len %d",
*out_len);
MOZ_MTLOG(ML_DEBUG, "Successfully unprotected an SRTCP packet of len "
<< *out_len);
return NS_OK;
}
@ -233,14 +228,14 @@ nsresult SrtpFlow::Init() {
if (!initialized) {
srtp_err_status_t r = srtp_init();
if (r != srtp_err_status_ok) {
CSFLogError(LOGTAG, "Could not initialize SRTP");
MOZ_MTLOG(ML_ERROR, "Could not initialize SRTP");
MOZ_ASSERT(PR_FALSE);
return NS_ERROR_FAILURE;
}
r = srtp_install_event_handler(&SrtpFlow::srtp_event_handler);
if (r != srtp_err_status_ok) {
CSFLogError(LOGTAG, "Could not install SRTP event handler");
MOZ_MTLOG(ML_ERROR, "Could not install SRTP event handler");
MOZ_ASSERT(PR_FALSE);
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -17,6 +17,7 @@ EXPORTS.mtransport += [
'../runnable_utils.h',
'../sigslot.h',
'../simpletokenbucket.h',
'../SrtpFlow.h',
'../stun_socket_filter.h',
'../transportflow.h',
'../transportlayer.h',
@ -24,6 +25,7 @@ EXPORTS.mtransport += [
'../transportlayerice.h',
'../transportlayerlog.h',
'../transportlayerloopback.h',
'../transportlayersrtp.h',
]
include('../common.build')

Просмотреть файл

@ -17,6 +17,7 @@ mtransport_lcppsrcs = [
'nrinterfaceprioritizer.cpp',
'rlogconnector.cpp',
'simpletokenbucket.cpp',
'SrtpFlow.cpp',
'stun_socket_filter.cpp',
'test_nr_socket.cpp',
'transportflow.cpp',
@ -25,6 +26,7 @@ mtransport_lcppsrcs = [
'transportlayerice.cpp',
'transportlayerlog.cpp',
'transportlayerloopback.cpp',
'transportlayersrtp.cpp',
]
mtransport_cppsrcs = [
@ -47,6 +49,8 @@ LOCAL_INCLUDES += [
'/media/mtransport/third_party/nrappkit/src/share',
'/media/mtransport/third_party/nrappkit/src/stats',
'/media/mtransport/third_party/nrappkit/src/util/libekr',
'/netwerk/srtp/src/crypto/include',
'/netwerk/srtp/src/include',
]
if CONFIG['OS_TARGET'] in ['Darwin', 'DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD']:

Просмотреть файл

@ -158,6 +158,7 @@ class TransportTestPeer : public sigslot::has_slots<> {
}
void Disconnect_s() {
disconnect_all();
if (flow_) {
flow_ = nullptr;
}

Просмотреть файл

@ -0,0 +1,267 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
// Original author: ekr@rtfm.com
#include "transportlayersrtp.h"
#include "transportlayerdtls.h"
#include "logging.h"
#include "nsError.h"
#include "mozilla/Assertions.h"
#include "transportlayerdtls.h"
#include "srtp.h"
#include "databuffer.h"
#include "nsAutoPtr.h"
namespace mozilla {
MOZ_MTLOG_MODULE("mtransport")
static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
TransportLayerSrtp::TransportLayerSrtp(TransportLayerDtls& dtls)
{
// We need to connect to the dtls layer, not the ice layer, because even
// though the packets that DTLS decrypts don't flow through us, we do base our
// keying information on the keying information established by the DTLS layer.
dtls.SignalStateChange.connect(this, &TransportLayerSrtp::StateChange);
TL_SET_STATE(dtls.state());
}
void
TransportLayerSrtp::WasInserted()
{
// Connect to the lower layers
if (!Setup()) {
TL_SET_STATE(TS_ERROR);
}
}
bool
TransportLayerSrtp::Setup()
{
CheckThread();
if (!downward_) {
MOZ_MTLOG(ML_ERROR, "SRTP layer with nothing below. This is useless");
return false;
}
// downward_ is the TransportLayerIce
downward_->SignalPacketReceived.connect(this, &TransportLayerSrtp::PacketReceived);
return true;
}
static bool
IsRtp(const unsigned char* aData, size_t aLen)
{
if (aLen < 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 ((aData[1] < 192) || (aData[1] > 207))
return true;
if (aData[1] == 192) // FIR
return false;
if (aData[1] == 193) // NACK, but could also be RTP. This makes us sad
return true; // but it's how webrtc.org behaves.
if (aData[1] == 194)
return true;
if (aData[1] == 195) // IJ.
return false;
if ((aData[1] > 195) && (aData[1] < 200)) // the > 195 is redundant
return true;
if ((aData[1] >= 200) && (aData[1] <= 207)) // SR, RR, SDES, BYE,
return false; // APP, RTPFB, PSFB, XR
MOZ_ASSERT(false); // Not reached, belt and suspenders.
return true;
}
TransportResult
TransportLayerSrtp::SendPacket(const unsigned char* data, size_t len)
{
if (len < 4) {
MOZ_ASSERT(false);
return TE_ERROR;
}
// Make copy and add some room to expand.
nsAutoPtr<DataBuffer> buf(
new DataBuffer(data, len, len + SRTP_MAX_EXPANSION));
int out_len;
nsresult res;
if (IsRtp(data, len)) {
MOZ_MTLOG(ML_INFO, "Attempting to protect RTP...");
res = mSendSrtp->ProtectRtp(
buf->data(), buf->len(), buf->capacity(), &out_len);
} else {
MOZ_MTLOG(ML_INFO, "Attempting to protect RTCP...");
res = mSendSrtp->ProtectRtcp(
buf->data(), buf->len(), buf->capacity(), &out_len);
}
if (NS_FAILED(res)) {
MOZ_MTLOG(ML_ERROR,
"Error protecting RTP/RTCP len=" << len
<< "[" << std::hex
<< buf->data()[0] << " "
<< buf->data()[1] << " "
<< buf->data()[2] << " "
<< buf->data()[3]
<< "]");
return TE_ERROR;
}
// paranoia; don't have uninitialized bytes included in data->len()
buf->SetLength(out_len);
TransportResult bytes = downward_->SendPacket(buf->data(), buf->len());
if (bytes == static_cast<int>(buf->len())) {
// Whole packet was written, but the encrypted length might be different.
// Don't confuse the caller.
return len;
}
if (bytes == TE_WOULDBLOCK) {
return TE_WOULDBLOCK;
}
return TE_ERROR;
}
void
TransportLayerSrtp::StateChange(TransportLayer* layer, State state)
{
if (state == TS_OPEN) {
TransportLayerDtls* dtls = static_cast<TransportLayerDtls*>(layer);
MOZ_ASSERT(dtls); // DTLS is mandatory
uint16_t cipher_suite;
nsresult res = dtls->GetSrtpCipher(&cipher_suite);
if (NS_FAILED(res)) {
MOZ_MTLOG(ML_ERROR, "Failed to negotiate DTLS-SRTP. This is an error");
TL_SET_STATE(TS_ERROR);
return;
}
// SRTP Key Exporter as per RFC 5764 S 4.2
unsigned char srtp_block[SRTP_TOTAL_KEY_LENGTH * 2];
res = dtls->ExportKeyingMaterial(
kDTLSExporterLabel, false, "", srtp_block, sizeof(srtp_block));
if (NS_FAILED(res)) {
MOZ_MTLOG(ML_ERROR, "Failed to compute DTLS-SRTP keys. This is an error");
TL_SET_STATE(TS_ERROR);
return;
}
// Slice and dice as per RFC 5764 S 4.2
unsigned char client_write_key[SRTP_TOTAL_KEY_LENGTH];
unsigned char server_write_key[SRTP_TOTAL_KEY_LENGTH];
int offset = 0;
memcpy(client_write_key, srtp_block + offset, SRTP_MASTER_KEY_LENGTH);
offset += SRTP_MASTER_KEY_LENGTH;
memcpy(server_write_key, srtp_block + offset, SRTP_MASTER_KEY_LENGTH);
offset += SRTP_MASTER_KEY_LENGTH;
memcpy(client_write_key + SRTP_MASTER_KEY_LENGTH,
srtp_block + offset,
SRTP_MASTER_SALT_LENGTH);
offset += SRTP_MASTER_SALT_LENGTH;
memcpy(server_write_key + SRTP_MASTER_KEY_LENGTH,
srtp_block + offset,
SRTP_MASTER_SALT_LENGTH);
offset += SRTP_MASTER_SALT_LENGTH;
MOZ_ASSERT(offset == sizeof(srtp_block));
unsigned char* write_key;
unsigned char* read_key;
if (dtls->role() == TransportLayerDtls::CLIENT) {
write_key = client_write_key;
read_key = server_write_key;
} else {
write_key = server_write_key;
read_key = client_write_key;
}
MOZ_ASSERT(!mSendSrtp && !mRecvSrtp);
mSendSrtp =
SrtpFlow::Create(cipher_suite, false, write_key, SRTP_TOTAL_KEY_LENGTH);
mRecvSrtp =
SrtpFlow::Create(cipher_suite, true, read_key, SRTP_TOTAL_KEY_LENGTH);
if (!mSendSrtp || !mRecvSrtp) {
MOZ_MTLOG(ML_ERROR, "Couldn't create SRTP flow.");
TL_SET_STATE(TS_ERROR);
return;
}
MOZ_MTLOG(ML_INFO, "Created SRTP flow!");
}
TL_SET_STATE(state);
}
void
TransportLayerSrtp::PacketReceived(TransportLayer* layer,
const unsigned char *data,
size_t len)
{
if (state() != TS_OPEN) {
return;
}
if (len < 4) {
return;
}
// not RTP/RTCP per RFC 7983
if (data[0] <= 127 || data[0] >= 192) {
return;
}
// Make a copy rather than cast away constness
auto innerData = MakeUnique<unsigned char[]>(len);
memcpy(innerData.get(), data, len);
int outLen;
nsresult res;
if (IsRtp(innerData.get(), len)) {
MOZ_MTLOG(ML_INFO, "Attempting to unprotect RTP...");
res = mRecvSrtp->UnprotectRtp(innerData.get(), len, len, &outLen);
} else {
MOZ_MTLOG(ML_INFO, "Attempting to unprotect RTCP...");
res = mRecvSrtp->UnprotectRtcp(innerData.get(), len, len, &outLen);
}
if (NS_SUCCEEDED(res)) {
SignalPacketReceived(this, innerData.get(), outLen);
} else {
MOZ_MTLOG(ML_ERROR,
"Error unprotecting RTP/RTCP len=" << len
<< "[" << std::hex
<< innerData[0] << " "
<< innerData[1] << " "
<< innerData[2] << " "
<< innerData[3]
<< "]");
}
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef transportlayersrtp_h__
#define transportlayersrtp_h__
#include <string>
#include "transportlayer.h"
#include "mozilla/RefPtr.h"
#include "SrtpFlow.h"
namespace mozilla {
class TransportLayerDtls;
class TransportLayerSrtp final : public TransportLayer {
public:
explicit TransportLayerSrtp(TransportLayerDtls& dtls);
virtual ~TransportLayerSrtp() {};
// Transport layer overrides.
void WasInserted() override;
TransportResult SendPacket(const unsigned char *data, size_t len) override;
// Signals
void StateChange(TransportLayer *layer, State state);
void PacketReceived(TransportLayer* layer, const unsigned char *data,
size_t len);
TRANSPORT_LAYER_ID("srtp")
private:
bool Setup();
DISALLOW_COPY_ASSIGN(TransportLayerSrtp);
RefPtr<SrtpFlow> mSendSrtp;
RefPtr<SrtpFlow> mRecvSrtp;
};
} // close namespace
#endif

Просмотреть файл

@ -24,6 +24,7 @@
#include "transportflow.h"
#include "transportlayerloopback.h"
#include "transportlayerdtls.h"
#include "transportlayersrtp.h"
#include "mozilla/SyncRunnable.h"
#include "mtransport_test_utils.h"
#include "SharedBuffer.h"
@ -169,57 +170,40 @@ class TransportInfo {
public:
TransportInfo() :
flow_(nullptr),
loopback_(nullptr),
dtls_(nullptr) {}
loopback_(nullptr) {}
static void InitAndConnect(TransportInfo &client, TransportInfo &server) {
client.Init(true);
server.Init(false);
client.PushLayers();
server.PushLayers();
client.Connect(&server);
server.Connect(&client);
}
void Init(bool client) {
nsresult res;
flow_ = new TransportFlow();
loopback_ = new TransportLayerLoopback();
dtls_ = new TransportLayerDtls();
res = loopback_->Init();
if (res != NS_OK) {
FreeLayers();
}
ASSERT_EQ((nsresult)NS_OK, res);
UniquePtr<TransportLayerLoopback> loopback(new TransportLayerLoopback);
UniquePtr<TransportLayerDtls> dtls(new TransportLayerDtls);
UniquePtr<TransportLayerSrtp> srtp(new TransportLayerSrtp(*dtls));
std::vector<uint16_t> ciphers;
ciphers.push_back(SRTP_AES128_CM_HMAC_SHA1_80);
dtls_->SetSrtpCiphers(ciphers);
dtls_->SetIdentity(DtlsIdentity::Generate());
dtls_->SetRole(client ? TransportLayerDtls::CLIENT :
dtls->SetSrtpCiphers(ciphers);
dtls->SetIdentity(DtlsIdentity::Generate());
dtls->SetRole(client ? TransportLayerDtls::CLIENT :
TransportLayerDtls::SERVER);
dtls_->SetVerificationAllowAll();
}
dtls->SetVerificationAllowAll();
void PushLayers() {
if (NS_FAILED(loopback_->Init())) {
delete loopback_;
loopback_ = nullptr;
}
ASSERT_EQ(NS_OK, loopback->Init());
ASSERT_EQ(NS_OK, dtls->Init());
ASSERT_EQ(NS_OK, srtp->Init());
if (NS_FAILED(dtls_->Init())) {
delete dtls_;
dtls_ = nullptr;
}
dtls->Chain(loopback.get());
srtp->Chain(loopback.get());
ASSERT_TRUE(loopback_);
ASSERT_TRUE(dtls_);
dtls_->Chain(loopback_);
flow_ = new TransportFlow();
loopback_ = loopback.release();
flow_->PushLayer(loopback_);
flow_->PushLayer(dtls_);
flow_->PushLayer(dtls.release());
flow_->PushLayer(srtp.release());
}
void Connect(TransportInfo* peer) {
@ -229,27 +213,16 @@ class TransportInfo {
loopback_->Connect(peer->loopback_);
}
// Free the memory allocated at the beginning of Init
// if failure occurs before layers setup.
void FreeLayers() {
delete loopback_;
loopback_ = nullptr;
delete dtls_;
dtls_ = nullptr;
}
void Shutdown() {
if (loopback_) {
loopback_->Disconnect();
}
loopback_ = nullptr;
dtls_ = nullptr;
flow_ = nullptr;
}
RefPtr<TransportFlow> flow_;
TransportLayerLoopback *loopback_;
TransportLayerDtls *dtls_;
};
class TestAgent {
@ -374,9 +347,9 @@ class TestAgentSend : public TestAgent {
nullptr,
test_utils->sts_target(),
false,
audio_stream_track_.get(),
audio_conduit_);
audio_pipeline->SetTrack(audio_stream_track_.get());
audio_pipeline->Start();
audio_pipeline_ = audio_pipeline;

Просмотреть файл

@ -675,8 +675,6 @@ protected:
UniquePtr<AudioConverter> mAudioConverter;
};
static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
MediaPipeline::MediaPipeline(const std::string& aPc,
DirectionType aDirection,
nsCOMPtr<nsIEventTarget> aMainThread,
@ -689,9 +687,7 @@ MediaPipeline::MediaPipeline(const std::string& aPc,
, mRtcp(nullptr, RTCP)
, mMainThread(aMainThread)
, mStsThread(aStsThread)
, mTransport(new PipelineTransport(this)) // PipelineTransport() will access
// this->mStsThread; moved here
// for safety
, mTransport(new PipelineTransport(aStsThread))
, mRtpPacketsSent(0)
, mRtcpPacketsSent(0)
, mRtpPacketsReceived(0)
@ -921,96 +917,23 @@ MediaPipeline::TransportReady_s(TransportInfo& aInfo)
mDescription.c_str(),
ToString(aInfo.mType));
// TODO(bcampen@mozilla.com): Should we disconnect from the flow on failure?
nsresult res;
// Now instantiate the SRTP objects
TransportLayerDtls* dtls = static_cast<TransportLayerDtls*>(
aInfo.mTransport->GetLayer(TransportLayerDtls::ID()));
MOZ_ASSERT(dtls); // DTLS is mandatory
uint16_t cipher_suite;
res = dtls->GetSrtpCipher(&cipher_suite);
if (NS_FAILED(res)) {
CSFLogError(LOGTAG, "Failed to negotiate DTLS-SRTP. This is an error");
aInfo.mState = StateType::MP_CLOSED;
UpdateRtcpMuxState(aInfo);
return res;
}
// SRTP Key Exporter as per RFC 5764 S 4.2
unsigned char srtp_block[SRTP_TOTAL_KEY_LENGTH * 2];
res = dtls->ExportKeyingMaterial(
kDTLSExporterLabel, false, "", srtp_block, sizeof(srtp_block));
if (NS_FAILED(res)) {
CSFLogError(LOGTAG, "Failed to compute DTLS-SRTP keys. This is an error");
aInfo.mState = StateType::MP_CLOSED;
UpdateRtcpMuxState(aInfo);
MOZ_CRASH(); // TODO: Remove once we have enough field experience to
// know it doesn't happen. bug 798797. Note that the
// code after this never executes.
return res;
}
// Slice and dice as per RFC 5764 S 4.2
unsigned char client_write_key[SRTP_TOTAL_KEY_LENGTH];
unsigned char server_write_key[SRTP_TOTAL_KEY_LENGTH];
int offset = 0;
memcpy(client_write_key, srtp_block + offset, SRTP_MASTER_KEY_LENGTH);
offset += SRTP_MASTER_KEY_LENGTH;
memcpy(server_write_key, srtp_block + offset, SRTP_MASTER_KEY_LENGTH);
offset += SRTP_MASTER_KEY_LENGTH;
memcpy(client_write_key + SRTP_MASTER_KEY_LENGTH,
srtp_block + offset,
SRTP_MASTER_SALT_LENGTH);
offset += SRTP_MASTER_SALT_LENGTH;
memcpy(server_write_key + SRTP_MASTER_KEY_LENGTH,
srtp_block + offset,
SRTP_MASTER_SALT_LENGTH);
offset += SRTP_MASTER_SALT_LENGTH;
MOZ_ASSERT(offset == sizeof(srtp_block));
unsigned char* write_key;
unsigned char* read_key;
if (dtls->role() == TransportLayerDtls::CLIENT) {
write_key = client_write_key;
read_key = server_write_key;
} else {
write_key = server_write_key;
read_key = client_write_key;
}
MOZ_ASSERT(!aInfo.mSendSrtp && !aInfo.mRecvSrtp);
aInfo.mSendSrtp =
SrtpFlow::Create(cipher_suite, false, write_key, SRTP_TOTAL_KEY_LENGTH);
aInfo.mRecvSrtp =
SrtpFlow::Create(cipher_suite, true, read_key, SRTP_TOTAL_KEY_LENGTH);
if (!aInfo.mSendSrtp || !aInfo.mRecvSrtp) {
CSFLogError(
LOGTAG, "Couldn't create SRTP flow for %s", ToString(aInfo.mType));
aInfo.mState = StateType::MP_CLOSED;
UpdateRtcpMuxState(aInfo);
return NS_ERROR_FAILURE;
}
if (mDirection == DirectionType::RECEIVE) {
CSFLogInfo(LOGTAG,
"Listening for %s packets received on %p",
ToString(aInfo.mType),
dtls->downward());
aInfo.mSrtp);
switch (aInfo.mType) {
case RTP:
dtls->downward()->SignalPacketReceived.connect(
aInfo.mSrtp->SignalPacketReceived.connect(
this, &MediaPipeline::RtpPacketReceived);
break;
case RTCP:
dtls->downward()->SignalPacketReceived.connect(
aInfo.mSrtp->SignalPacketReceived.connect(
this, &MediaPipeline::RtcpPacketReceived);
break;
case MUX:
dtls->downward()->SignalPacketReceived.connect(
aInfo.mSrtp->SignalPacketReceived.connect(
this, &MediaPipeline::PacketReceived);
break;
default:
@ -1050,10 +973,6 @@ MediaPipeline::UpdateRtcpMuxState(TransportInfo& aInfo)
if (aInfo.mType == MUX) {
if (aInfo.mTransport == mRtcp.mTransport) {
mRtcp.mState = aInfo.mState;
if (!mRtcp.mSendSrtp) {
mRtcp.mSendSrtp = aInfo.mSendSrtp;
mRtcp.mRecvSrtp = aInfo.mRecvSrtp;
}
}
}
}
@ -1166,14 +1085,11 @@ MediaPipeline::RtpPacketReceived(TransportLayer* aLayer,
return;
}
if (mRtp.mDtls->state() != TransportLayer::TS_OPEN) {
if (mRtp.mSrtp->state() != TransportLayer::TS_OPEN) {
CSFLogError(LOGTAG, "Discarding incoming packet; transport not open");
return;
}
// This should never happen.
MOZ_ASSERT(mRtp.mRecvSrtp);
if (!aLen) {
return;
}
@ -1232,41 +1148,18 @@ MediaPipeline::RtpPacketReceived(TransportLayer* aLayer,
mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Srtp, false, aData, aLen);
// Make a copy rather than cast away constness
auto innerData = MakeUnique<unsigned char[]>(aLen);
memcpy(innerData.get(), aData, aLen);
int outLen = 0;
nsresult res =
mRtp.mRecvSrtp->UnprotectRtp(innerData.get(), aLen, aLen, &outLen);
if (!NS_SUCCEEDED(res)) {
char tmp[16];
SprintfLiteral(tmp,
"%.2x %.2x %.2x %.2x",
innerData[0],
innerData[1],
innerData[2],
innerData[3]);
CSFLogError(LOGTAG,
"Error unprotecting RTP in %s len= %zu [%s]",
mDescription.c_str(),
aLen,
tmp);
return;
}
CSFLogDebug(LOGTAG, "%s received RTP packet.", mDescription.c_str());
IncrementRtpPacketsReceived(outLen);
IncrementRtpPacketsReceived(aLen);
OnRtpPacketReceived();
RtpLogger::LogPacket(
innerData.get(), outLen, true, true, header.headerLength, mDescription);
aData, aLen, true, true, header.headerLength, mDescription);
mPacketDumper->Dump(
mLevel, dom::mozPacketDumpType::Rtp, false, innerData.get(), outLen);
mLevel, dom::mozPacketDumpType::Rtp, false, aData, aLen);
(void)mConduit->ReceivedRTPPacket(
innerData.get(), outLen, header.ssrc); // Ignore error codes
aData, aLen, header.ssrc); // Ignore error codes
}
void
@ -1289,7 +1182,7 @@ MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer,
return;
}
if (mRtcp.mDtls->state() != TransportLayer::TS_OPEN) {
if (mRtcp.mSrtp->state() != TransportLayer::TS_OPEN) {
CSFLogError(LOGTAG, "Discarding incoming packet; transport not open");
return;
}
@ -1313,28 +1206,14 @@ MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer,
mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Srtcp, false, aData, aLen);
// Make a copy rather than cast away constness
auto innerData = MakeUnique<unsigned char[]>(aLen);
memcpy(innerData.get(), aData, aLen);
int outLen;
nsresult res =
mRtcp.mRecvSrtp->UnprotectRtcp(innerData.get(), aLen, aLen, &outLen);
if (!NS_SUCCEEDED(res))
return;
CSFLogDebug(LOGTAG, "%s received RTCP packet.", mDescription.c_str());
IncrementRtcpPacketsReceived();
RtpLogger::LogPacket(innerData.get(), outLen, true, false, 0, mDescription);
RtpLogger::LogPacket(aData, aLen, true, false, 0, mDescription);
mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Rtcp, false, aData, aLen);
MOZ_ASSERT(mRtcp.mRecvSrtp); // This should never happen
(void)mConduit->ReceivedRTCPPacket(innerData.get(),
outLen); // Ignore error codes
(void)mConduit->ReceivedRTCPPacket(aData, aLen); // Ignore error codes
}
bool
@ -1514,7 +1393,6 @@ MediaPipelineTransmit::MediaPipelineTransmit(
nsCOMPtr<nsIEventTarget> aMainThread,
nsCOMPtr<nsIEventTarget> aStsThread,
bool aIsVideo,
dom::MediaStreamTrack* aDomTrack,
RefPtr<MediaSessionConduit> aConduit)
: MediaPipeline(aPc,
DirectionType::TRANSMIT,
@ -1529,10 +1407,8 @@ MediaPipelineTransmit::MediaPipelineTransmit(
// calls back to a VideoFrameFeeder
// that feeds I420 frames to
// VideoConduit.
, mDomTrack(aDomTrack)
, mTransmitting(false)
{
SetDescription();
if (!IsVideo()) {
mAudioProcessing = MakeAndAddRef<AudioProxyThread>(
static_cast<AudioSessionConduit*>(aConduit.get()));
@ -1714,7 +1590,7 @@ MediaPipelineTransmit::TransportReady_s(TransportInfo& aInfo)
}
nsresult
MediaPipelineTransmit::ReplaceTrack(RefPtr<MediaStreamTrack>& aDomTrack)
MediaPipelineTransmit::SetTrack(MediaStreamTrack* aDomTrack)
{
// MainThread, checked in calls we make
if (aDomTrack) {
@ -1745,11 +1621,11 @@ nsresult
MediaPipeline::ConnectTransport_s(TransportInfo& aInfo)
{
MOZ_ASSERT(aInfo.mTransport);
MOZ_ASSERT(aInfo.mDtls);
MOZ_ASSERT(aInfo.mSrtp);
ASSERT_ON_THREAD(mStsThread);
// Look to see if the transport is ready
if (aInfo.mDtls->state() == TransportLayer::TS_OPEN) {
if (aInfo.mSrtp->state() == TransportLayer::TS_OPEN) {
nsresult res = TransportReady_s(aInfo);
if (NS_FAILED(res)) {
CSFLogError(LOGTAG,
@ -1758,14 +1634,14 @@ MediaPipeline::ConnectTransport_s(TransportInfo& aInfo)
__FUNCTION__);
return res;
}
} else if (aInfo.mDtls->state() == TransportLayer::TS_ERROR) {
} else if (aInfo.mSrtp->state() == TransportLayer::TS_ERROR) {
CSFLogError(
LOGTAG, "%s transport is already in error state", ToString(aInfo.mType));
TransportFailed_s(aInfo);
return NS_ERROR_FAILURE;
}
aInfo.mDtls->SignalStateChange.connect(this, &MediaPipeline::StateChange);
aInfo.mSrtp->SignalStateChange.connect(this, &MediaPipeline::StateChange);
return NS_OK;
}
@ -1774,11 +1650,11 @@ MediaPipeline::TransportInfo*
MediaPipeline::GetTransportInfo_s(TransportLayer* aLayer)
{
ASSERT_ON_THREAD(mStsThread);
if (aLayer == mRtp.mDtls) {
if (aLayer == mRtp.mSrtp) {
return &mRtp;
}
if (aLayer == mRtcp.mDtls) {
if (aLayer == mRtcp.mSrtp) {
return &mRtcp;
}
@ -1788,9 +1664,8 @@ MediaPipeline::GetTransportInfo_s(TransportLayer* aLayer)
nsresult
MediaPipeline::PipelineTransport::SendRtpPacket(const uint8_t* aData, size_t aLen)
{
nsAutoPtr<DataBuffer> buf(
new DataBuffer(aData, aLen, aLen + SRTP_MAX_EXPANSION));
// Might be nice to avoid this copy.
nsAutoPtr<DataBuffer> buf(new DataBuffer(aData, aLen));
RUN_ON_THREAD(
mStsThread,
@ -1808,24 +1683,20 @@ MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
nsAutoPtr<DataBuffer> aData,
bool aIsRtp)
{
ASSERT_ON_THREAD(mStsThread);
if (!mPipeline) {
return NS_OK; // Detached
}
TransportInfo& transport = aIsRtp ? mPipeline->mRtp : mPipeline->mRtcp;
if (!transport.mSendSrtp) {
CSFLogDebug(LOGTAG, "Couldn't write RTP/RTCP packet; SRTP not set up yet");
if (transport.mSrtp->state() != TransportLayer::TS_OPEN) {
// SRTP not ready yet.
return NS_OK;
}
MOZ_ASSERT(transport.mTransport);
NS_ENSURE_TRUE(transport.mTransport, NS_ERROR_NULL_POINTER);
// libsrtp enciphers in place, so we need a big enough buffer.
MOZ_ASSERT(aData->capacity() >= aData->len() + SRTP_MAX_EXPANSION);
if (RtpLogger::IsPacketLoggingOn()) {
int headerLen = 12;
webrtc::RTPHeader header;
@ -1841,65 +1712,36 @@ MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
mPipeline->mDescription);
}
int out_len;
nsresult res;
if (aIsRtp) {
mPipeline->mPacketDumper->Dump(mPipeline->Level(),
dom::mozPacketDumpType::Rtp,
true,
aData->data(),
aData->len());
res = transport.mSendSrtp->ProtectRtp(
aData->data(), aData->len(), aData->capacity(), &out_len);
mPipeline->IncrementRtpPacketsSent(aData->len());
} else {
mPipeline->mPacketDumper->Dump(mPipeline->Level(),
dom::mozPacketDumpType::Rtcp,
true,
aData->data(),
aData->len());
res = transport.mSendSrtp->ProtectRtcp(
aData->data(), aData->len(), aData->capacity(), &out_len);
mPipeline->IncrementRtcpPacketsSent();
}
if (!NS_SUCCEEDED(res)) {
return res;
}
// paranoia; don't have uninitialized bytes included in data->len()
aData->SetLength(out_len);
CSFLogDebug(LOGTAG,
"%s sending %s packet",
mPipeline->mDescription.c_str(),
(aIsRtp ? "RTP" : "RTCP"));
if (aIsRtp) {
mPipeline->mPacketDumper->Dump(mPipeline->Level(),
dom::mozPacketDumpType::Srtp,
true,
aData->data(),
out_len);
mPipeline->IncrementRtpPacketsSent(out_len);
} else {
mPipeline->mPacketDumper->Dump(mPipeline->Level(),
dom::mozPacketDumpType::Srtcp,
true,
aData->data(),
out_len);
mPipeline->IncrementRtcpPacketsSent();
}
return mPipeline->SendPacket(transport.mDtls->downward(), aData->data(), out_len);
return mPipeline->SendPacket(transport.mSrtp, aData->data(), aData->len());
}
nsresult
MediaPipeline::PipelineTransport::SendRtcpPacket(const uint8_t* aData,
size_t aLen)
{
nsAutoPtr<DataBuffer> buf(
new DataBuffer(aData, aLen, aLen + SRTP_MAX_EXPANSION));
// Might be nice to avoid this copy.
nsAutoPtr<DataBuffer> buf(new DataBuffer(aData, aLen));
RUN_ON_THREAD(
mStsThread,

Просмотреть файл

@ -185,9 +185,9 @@ public:
{
public:
// Implement the TransportInterface functions
explicit PipelineTransport(MediaPipeline* aPipeline)
: mPipeline(aPipeline)
, mStsThread(aPipeline->mStsThread)
explicit PipelineTransport(nsIEventTarget* aStsThread)
: mPipeline(nullptr)
, mStsThread(aStsThread)
{
}
@ -215,7 +215,7 @@ protected:
{
TransportInfo(RefPtr<TransportFlow> aFlow, RtpType aType)
: mTransport(aFlow)
, mDtls(mTransport ? mTransport->GetLayer("dtls") : nullptr)
, mSrtp(mTransport ? mTransport->GetLayer("srtp") : nullptr)
, mState(StateType::MP_CONNECTING)
, mType(aType)
{
@ -224,16 +224,12 @@ protected:
void Detach()
{
mTransport = nullptr;
mDtls = nullptr;
mSendSrtp = nullptr;
mRecvSrtp = nullptr;
mSrtp = nullptr;
}
RefPtr<TransportFlow> mTransport;
TransportLayer* mDtls;
TransportLayer* mSrtp;
StateType mState;
RefPtr<SrtpFlow> mSendSrtp;
RefPtr<SrtpFlow> mRecvSrtp;
RtpType mType;
};
@ -329,7 +325,6 @@ public:
nsCOMPtr<nsIEventTarget> aMainThread,
nsCOMPtr<nsIEventTarget> aStsThread,
bool aIsVideo,
dom::MediaStreamTrack* aDomTrack,
RefPtr<MediaSessionConduit> aConduit);
void Start() override;
@ -355,7 +350,7 @@ public:
// In non-compliance with the likely final spec, allow the new
// track to be part of a different stream (since we don't support
// multiple tracks of a type in a stream yet). bug 1056650
virtual nsresult ReplaceTrack(RefPtr<dom::MediaStreamTrack>& aDomTrack);
virtual nsresult SetTrack(dom::MediaStreamTrack* aDomTrack);
// Separate classes to allow ref counting
class PipelineListener;

Просмотреть файл

@ -23,7 +23,6 @@ UNIFIED_SOURCES += [
'MediaPipeline.cpp',
'MediaPipelineFilter.cpp',
'RtpLogger.cpp',
'SrtpFlow.cpp',
]
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -19,6 +19,7 @@
#include "runnable_utils.h"
#include "transportlayerice.h"
#include "transportlayerdtls.h"
#include "transportlayersrtp.h"
#include "signaling/src/jsep/JsepSession.h"
#include "signaling/src/jsep/JsepTransport.h"
@ -530,16 +531,20 @@ FinalizeTransportFlow_s(RefPtr<PeerConnectionMedia> aPCMedia,
RefPtr<TransportFlow> aFlow, size_t aLevel,
bool aIsRtcp,
TransportLayerIce* aIceLayer,
TransportLayerDtls* aDtlsLayer)
TransportLayerDtls* aDtlsLayer,
TransportLayerSrtp* aSrtpLayer)
{
aIceLayer->SetParameters(aPCMedia->ice_media_stream(aLevel),
aIsRtcp ? 2 : 1);
// TODO(bug 854518): Process errors.
(void)aIceLayer->Init();
(void)aDtlsLayer->Init();
(void)aSrtpLayer->Init();
aDtlsLayer->Chain(aIceLayer);
aSrtpLayer->Chain(aIceLayer);
aFlow->PushLayer(aIceLayer);
aFlow->PushLayer(aDtlsLayer);
aFlow->PushLayer(aSrtpLayer);
}
static void
@ -599,6 +604,7 @@ PeerConnectionMedia::UpdateTransportFlow(
// The media streams are made on STS so we need to defer setup.
auto ice = MakeUnique<TransportLayerIce>();
auto dtls = MakeUnique<TransportLayerDtls>();
auto srtp = MakeUnique<TransportLayerSrtp>(*dtls);
dtls->SetRole(aTransport.mDtls->GetRole() ==
JsepDtlsTransport::kJsepDtlsClient
? TransportLayerDtls::CLIENT
@ -653,7 +659,7 @@ PeerConnectionMedia::UpdateTransportFlow(
RefPtr<PeerConnectionMedia> pcMedia(this);
rv = GetSTSThread()->Dispatch(
WrapRunnableNM(FinalizeTransportFlow_s, pcMedia, flow, aLevel, aIsRtcp,
ice.release(), dtls.release()),
ice.release(), dtls.release(), srtp.release()),
NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
CSFLogError(LOGTAG, "Failed to dispatch FinalizeTransportFlow_s");

Просмотреть файл

@ -69,8 +69,9 @@ TransceiverImpl::TransceiverImpl(
mMainThread.get(),
mStsThread.get(),
IsVideo(),
mSendTrack,
mConduit);
mTransmitPipeline->SetTrack(mSendTrack);
}
TransceiverImpl::~TransceiverImpl() = default;
@ -158,7 +159,7 @@ TransceiverImpl::UpdateSendTrack(dom::MediaStreamTrack* aSendTrack)
MOZ_MTLOG(ML_DEBUG, mPCHandle << "[" << mMid << "]: " << __FUNCTION__ <<
"(" << aSendTrack << ")");
mSendTrack = aSendTrack;
return mTransmitPipeline->ReplaceTrack(mSendTrack);
return mTransmitPipeline->SetTrack(mSendTrack);
}
nsresult