Bug 1486012: Rework ICE restart. r=mjf

Differential Revision: https://phabricator.services.mozilla.com/D5897

--HG--
rename : dom/media/tests/mochitest/test_peerConnection_restartIceLocalAndRemoteRollback.html => dom/media/tests/mochitest/test_peerConnection_restartIceLocalAndRemoteRollbackNoSubsequentRestart.html
rename : dom/media/tests/mochitest/test_peerConnection_restartIceLocalRollback.html => dom/media/tests/mochitest/test_peerConnection_restartIceLocalRollbackNoSubsequentRestart.html
extra : moz-landing-system : lando
This commit is contained in:
Byron Campen [:bwc] 2018-09-20 16:07:51 +00:00
Родитель f3e06a8e36
Коммит 93985b16c9
41 изменённых файлов: 973 добавлений и 1421 удалений

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

@ -231,8 +231,12 @@ skip-if = toolkit == 'android'
skip-if = toolkit == 'android'
[test_peerConnection_restartIceLocalRollback.html]
skip-if = toolkit == 'android'
[test_peerConnection_restartIceLocalRollbackNoSubsequentRestart.html]
skip-if = toolkit == 'android'
[test_peerConnection_restartIceLocalAndRemoteRollback.html]
skip-if = toolkit == 'android'
[test_peerConnection_restartIceLocalAndRemoteRollbackNoSubsequentRestart.html]
skip-if = toolkit == 'android'
[test_peerConnection_restartIceBadAnswer.html]
skip-if = toolkit == 'android'
[test_peerConnection_scaleResolution.html]

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

@ -64,13 +64,13 @@
STABLE);
},
// Rolling back should shut down gathering
// Rolling back should shut down gathering for the offerer,
// but because the answerer never set a local description, no ICE
// gathering has happened yet, so there's no changes to ICE gathering
// state
function PC_LOCAL_WAIT_FOR_END_OF_TRICKLE(test) {
return test.pcLocal.endOfTrickleIce;
},
function PC_REMOTE_WAIT_FOR_END_OF_TRICKLE(test) {
return test.pcRemote.endOfTrickleIce;
},
function PC_LOCAL_EXPECT_ICE_CHECKING(test) {
test.pcLocal.expectIceChecking();

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

@ -0,0 +1,86 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "906986",
title: "Renegotiation: restart ice, local and remote rollback, without a subsequent ICE restart"
});
var test;
runNetworkTest(function (options) {
test = new PeerConnectionTest(options);
addRenegotiation(test.chain,
[
// causes a full, normal ice restart
function PC_LOCAL_SET_OFFER_OPTION(test) {
test.setOfferOptions({ iceRestart: true });
}
]
);
test.chain.replaceAfter('PC_REMOTE_CREATE_ANSWER',
[
function PC_LOCAL_SETUP_ICE_HANDLER(test) {
test.pcLocal.setupIceCandidateHandler(test);
if (test.testOptions.steeplechase) {
test.pcLocal.endOfTrickleIce.then(() => {
send_message({"type": "end_of_trickle_ice"});
});
}
},
function PC_REMOTE_SETUP_ICE_HANDLER(test) {
test.pcRemote.setupIceCandidateHandler(test);
if (test.testOptions.steeplechase) {
test.pcRemote.endOfTrickleIce.then(() => {
send_message({"type": "end_of_trickle_ice"});
});
}
},
function PC_REMOTE_ROLLBACK(test) {
return test.setRemoteDescription(test.pcRemote, { type: "rollback" },
STABLE);
},
function PC_LOCAL_ROLLBACK(test) {
// We haven't negotiated the new stream yet.
test.pcLocal.expectNegotiationNeeded();
return test.setLocalDescription(
test.pcLocal,
new RTCSessionDescription({ type: "rollback", sdp: ""}),
STABLE);
},
// Rolling back should shut down gathering for the offerer,
// but because the answerer never set a local description, no ICE
// gathering has happened yet, so there's no changes to ICE gathering
// state
function PC_LOCAL_WAIT_FOR_END_OF_TRICKLE(test) {
return test.pcLocal.endOfTrickleIce;
},
function PC_LOCAL_SET_OFFER_OPTION(test) {
test.setOfferOptions({ iceRestart: false });
}
],
1 // Replaces after second PC_REMOTE_CREATE_ANSWER
);
test.chain.append(commandsPeerConnectionOfferAnswer);
// for now, only use one stream, because rollback doesn't seem to
// like multiple streams. See bug 1259465.
test.setMediaConstraints([{audio: true}],
[{audio: true}]);
test.run();
});
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,66 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "906986",
title: "Renegotiation: restart ice, local rollback, then renegotiation without ICE restart"
});
var test;
runNetworkTest(function (options) {
test = new PeerConnectionTest(options);
addRenegotiation(test.chain,
[
// causes a full, normal ice restart
function PC_LOCAL_SET_OFFER_OPTION(test) {
test.setOfferOptions({ iceRestart: true });
},
// causes an ice restart and then rolls it back
// (does not result in sending an offer)
function PC_LOCAL_SETUP_ICE_HANDLER(test) {
test.pcLocal.setupIceCandidateHandler(test);
if (test.testOptions.steeplechase) {
test.pcLocal.endOfTrickleIce.then(() => {
send_message({"type": "end_of_trickle_ice"});
});
}
},
function PC_LOCAL_CREATE_AND_SET_OFFER(test) {
return test.createOffer(test.pcLocal).then(offer => {
return test.setLocalDescription(test.pcLocal,
offer,
HAVE_LOCAL_OFFER);
});
},
function PC_LOCAL_ROLLBACK(test) {
return test.setLocalDescription(test.pcLocal,
{ type: "rollback", sdp: ""},
STABLE);
},
// Rolling back should shut down gathering
function PC_LOCAL_WAIT_FOR_END_OF_TRICKLE(test) {
return test.pcLocal.endOfTrickleIce;
},
function PC_LOCAL_SET_OFFER_OPTION(test) {
test.setOfferOptions({ iceRestart: false });
}
]
);
// for now, only use one stream, because rollback doesn't seem to
// like multiple streams. See bug 1259465.
test.setMediaConstraints([{audio: true}],
[{audio: true}]);
test.run();
});
</script>
</pre>
</body>
</html>

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

@ -10,7 +10,6 @@ mtransport_lcppsrcs = [
'nr_socket_prsock.cpp',
'nr_timer.cpp',
'nricectx.cpp',
'nricectxhandler.cpp',
'nricemediastream.cpp',
'nriceresolver.cpp',
'nriceresolverfake.cpp',

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

@ -291,18 +291,68 @@ NrIceCtx::NrIceCtx(const std::string& name, Policy policy)
nat_ (nullptr) {
}
/* static */
RefPtr<NrIceCtx>
NrIceCtx::Create(const std::string& name,
bool allow_loopback,
bool tcp_enabled,
bool allow_link_local,
Policy policy)
{
// InitializeGlobals only executes once
NrIceCtx::InitializeGlobals(allow_loopback, tcp_enabled, allow_link_local);
RefPtr<NrIceCtx> ctx = new NrIceCtx(name, policy);
if (!ctx->Initialize()) {
return nullptr;
}
return ctx;
}
RefPtr<NrIceMediaStream>
NrIceCtx::CreateStream(const std::string& id,
const std::string& name,
int components)
{
if (streams_.count(id)) {
MOZ_ASSERT(false);
return nullptr;
}
RefPtr<NrIceMediaStream> stream =
new NrIceMediaStream(this, id, name, components);
streams_[id] = stream;
return stream;
}
void
NrIceCtx::DestroyStream(const std::string& id) {
auto it = streams_.find(id);
if (it != streams_.end()) {
auto preexisting_stream = it->second;
streams_.erase(it);
preexisting_stream->Close();
}
}
// Handler callbacks
int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream,
int component_id, nr_ice_cand_pair **potentials,
int potential_ct) {
MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = "
<< potential_ct);
MOZ_ASSERT(stream->local_stream);
MOZ_ASSERT(!stream->local_stream->obsolete);
return 0;
}
int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) {
MOZ_MTLOG(ML_DEBUG, "stream_ready called");
MOZ_ASSERT(!stream->local_stream);
MOZ_ASSERT(!stream->obsolete);
// Get the ICE ctx.
NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
@ -319,6 +369,8 @@ int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) {
int NrIceCtx::stream_failed(void *obj, nr_ice_media_stream *stream) {
MOZ_MTLOG(ML_DEBUG, "stream_failed called");
MOZ_ASSERT(!stream->local_stream);
MOZ_ASSERT(!stream->obsolete);
// Get the ICE ctx
NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
@ -328,7 +380,7 @@ int NrIceCtx::stream_failed(void *obj, nr_ice_media_stream *stream) {
MOZ_ASSERT(s);
ctx->SetConnectionState(ICE_CTX_FAILED);
s -> SignalFailed(s);
s -> Failed();
return 0;
}
@ -387,6 +439,7 @@ void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx,
nr_ice_media_stream *stream,
int component_id,
nr_ice_candidate *candidate) {
MOZ_ASSERT(!stream->obsolete);
// Get the ICE ctx
NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
@ -488,40 +541,6 @@ NrIceCtx::InitializeGlobals(bool allow_loopback,
}
}
std::string
NrIceCtx::GetNewUfrag()
{
char* ufrag;
int r;
if ((r=nr_ice_get_new_ice_ufrag(&ufrag))) {
MOZ_CRASH("Unable to get new ice ufrag");
return "";
}
std::string ufragStr = ufrag;
RFREE(ufrag);
return ufragStr;
}
std::string
NrIceCtx::GetNewPwd()
{
char* pwd;
int r;
if ((r=nr_ice_get_new_ice_pwd(&pwd))) {
MOZ_CRASH("Unable to get new ice pwd");
return "";
}
std::string pwdStr = pwd;
RFREE(pwd);
return pwdStr;
}
#define MAXADDRS 100 // mirrors setting in ice_ctx.c
/* static */
@ -570,22 +589,6 @@ NrIceCtx::SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs)
bool
NrIceCtx::Initialize()
{
std::string ufrag = GetNewUfrag();
std::string pwd = GetNewPwd();
return Initialize(ufrag, pwd);
}
bool
NrIceCtx::Initialize(const std::string& ufrag,
const std::string& pwd)
{
MOZ_ASSERT(!ufrag.empty());
MOZ_ASSERT(!pwd.empty());
if (ufrag.empty() || pwd.empty()) {
return false;
}
// Create the ICE context
int r;
@ -601,13 +604,7 @@ NrIceCtx::Initialize(const std::string& ufrag,
break;
}
r = nr_ice_ctx_create_with_credentials(const_cast<char *>(name_.c_str()),
flags,
const_cast<char *>(ufrag.c_str()),
const_cast<char *>(pwd.c_str()),
&ctx_);
MOZ_ASSERT(ufrag == ctx_->ufrag);
MOZ_ASSERT(pwd == ctx_->pwd);
r = nr_ice_ctx_create(const_cast<char *>(name_.c_str()), flags, &ctx_);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name_ << "'");
@ -792,29 +789,6 @@ NrIceCtx::~NrIceCtx() {
Destroy();
}
void
NrIceCtx::SetStream(const std::string& id, NrIceMediaStream* stream) {
auto it = streams_.find(id);
if (it != streams_.end()) {
MOZ_ASSERT(!stream, "Transport ids should be unique, and set only once");
auto preexisting_stream = it->second;
streams_.erase(it);
preexisting_stream->Close();
}
if (stream) {
streams_[id] = stream;
}
}
std::string NrIceCtx::ufrag() const {
return ctx_->ufrag;
}
std::string NrIceCtx::pwd() const {
return ctx_->pwd;
}
void NrIceCtx::destroy_peer_ctx() {
nr_ice_peer_ctx_destroy(&peer_);
}
@ -992,7 +966,7 @@ nsresult NrIceCtx::StartGathering(bool default_route_only, bool proxy_only) {
RefPtr<NrIceMediaStream> NrIceCtx::FindStream(nr_ice_media_stream *stream) {
for (auto& idAndStream : streams_) {
if (idAndStream.second->stream() == stream) {
if (idAndStream.second->HasStream(stream)) {
return idAndStream.second;
}
}

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

@ -68,6 +68,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "m_cpp_utils.h"
#include "nricestunaddr.h"
#include "nricemediastream.h"
typedef struct nr_ice_ctx_ nr_ice_ctx;
typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx;
@ -204,7 +205,6 @@ class NrIceStats {
};
class NrIceCtx {
friend class NrIceCtxHandler;
public:
enum ConnectionState { ICE_CTX_INIT,
ICE_CTX_CHECKING,
@ -229,12 +229,22 @@ class NrIceCtx {
ICE_POLICY_ALL
};
static RefPtr<NrIceCtx> Create(const std::string& name,
bool allow_loopback = false,
bool tcp_enabled = true,
bool allow_link_local = false,
NrIceCtx::Policy policy =
NrIceCtx::ICE_POLICY_ALL);
RefPtr<NrIceMediaStream> CreateStream(const std::string& id,
const std::string& name,
int components);
void DestroyStream(const std::string& id);
// initialize ICE globals, crypto, and logging
static void InitializeGlobals(bool allow_loopback = false,
bool tcp_enabled = true,
bool allow_link_local = false);
static std::string GetNewUfrag();
static std::string GetNewPwd();
// static GetStunAddrs for use in parent process to support
// sandboxing restrictions
@ -242,7 +252,6 @@ class NrIceCtx {
void SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs);
bool Initialize();
bool Initialize(const std::string& ufrag, const std::string& pwd);
int SetNat(const RefPtr<TestNat>& aNat);
@ -258,8 +267,6 @@ class NrIceCtx {
// Testing only.
void destroy_peer_ctx();
void SetStream(const std::string& id, NrIceMediaStream* stream);
RefPtr<NrIceMediaStream> GetStream(const std::string& id) {
auto it = streams_.find(id);
if (it != streams_.end()) {
@ -281,10 +288,6 @@ class NrIceCtx {
// The name of the ctx
const std::string& name() const { return name_; }
// Get ufrag and password.
std::string ufrag() const;
std::string pwd() const;
// Current state
ConnectionState connection_state() const {
return connection_state_;

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

@ -1,188 +0,0 @@
#include <sstream>
#include "logging.h"
// nICEr includes
extern "C" {
#include "nr_api.h"
#include "ice_ctx.h"
}
// Local includes
#include "nricectxhandler.h"
#include "nricemediastream.h"
#include "nriceresolver.h"
namespace mozilla {
MOZ_MTLOG_MODULE("mtransport")
NrIceCtxHandler::NrIceCtxHandler(const std::string& name,
NrIceCtx::Policy policy)
: current_ctx(new NrIceCtx(name, policy)),
old_ctx(nullptr),
restart_count(0)
{
}
RefPtr<NrIceCtxHandler>
NrIceCtxHandler::Create(const std::string& name,
bool allow_loopback,
bool tcp_enabled,
bool allow_link_local,
NrIceCtx::Policy policy)
{
// InitializeGlobals only executes once
NrIceCtx::InitializeGlobals(allow_loopback, tcp_enabled, allow_link_local);
RefPtr<NrIceCtxHandler> ctx = new NrIceCtxHandler(name, policy);
if (ctx == nullptr ||
ctx->current_ctx == nullptr ||
!ctx->current_ctx->Initialize()) {
return nullptr;
}
return ctx;
}
RefPtr<NrIceMediaStream>
NrIceCtxHandler::CreateStream(const std::string& name, int components)
{
// To make tracking NrIceMediaStreams easier during ICE restart
// prepend an int to the name that increments with each ICE restart
std::ostringstream os;
os << restart_count << "-" << name;
return NrIceMediaStream::Create(this->current_ctx, os.str(), components);
}
RefPtr<NrIceCtx>
NrIceCtxHandler::CreateCtx() const
{
return CreateCtx(NrIceCtx::GetNewUfrag(), NrIceCtx::GetNewPwd());
}
RefPtr<NrIceCtx>
NrIceCtxHandler::CreateCtx(const std::string& ufrag,
const std::string& pwd) const
{
RefPtr<NrIceCtx> new_ctx = new NrIceCtx(this->current_ctx->name(),
this->current_ctx->policy());
if (new_ctx == nullptr) {
return nullptr;
}
if (!new_ctx->Initialize(ufrag, pwd)) {
return nullptr;
}
// copy the stun, and turn servers from the current context
int r = nr_ice_ctx_set_stun_servers(new_ctx->ctx_,
this->current_ctx->ctx_->stun_servers,
this->current_ctx->ctx_->stun_server_ct);
if (r) {
MOZ_MTLOG(ML_ERROR, "Error while setting STUN servers in CreateCtx"
<< " (likely ice restart related)");
return nullptr;
}
r = nr_ice_ctx_copy_turn_servers(new_ctx->ctx_,
this->current_ctx->ctx_->turn_servers,
this->current_ctx->ctx_->turn_server_ct);
if (r) {
MOZ_MTLOG(ML_ERROR, "Error while copying TURN servers in CreateCtx"
<< " (likely ice restart related)");
return nullptr;
}
// grab the NrIceResolver stashed in the nr_resolver and allocate another
// for the new ctx. Note: there may not be an nr_resolver.
if (this->current_ctx->ctx_->resolver) {
NrIceResolver* resolver =
static_cast<NrIceResolver*>(this->current_ctx->ctx_->resolver->obj);
if (!resolver ||
NS_FAILED(new_ctx->SetResolver(resolver->AllocateResolver()))) {
MOZ_MTLOG(ML_ERROR, "Error while setting dns resolver in CreateCtx"
<< " (likely ice restart related)");
return nullptr;
}
}
return new_ctx;
}
bool
NrIceCtxHandler::BeginIceRestart(RefPtr<NrIceCtx> new_ctx)
{
MOZ_ASSERT(!old_ctx, "existing ice restart in progress");
if (old_ctx) {
MOZ_MTLOG(ML_ERROR, "Existing ice restart in progress");
return false; // ice restart already in progress
}
if (new_ctx == nullptr) {
return false;
}
++restart_count;
old_ctx = current_ctx;
current_ctx = new_ctx;
return true;
}
void
NrIceCtxHandler::FinalizeIceRestart()
{
if (old_ctx) {
// Fixup the telemetry by transferring old stats to current ctx.
NrIceStats stats = old_ctx->Destroy();
current_ctx->AccumulateStats(stats);
}
// no harm calling this even if we're not in the middle of restarting
old_ctx = nullptr;
}
void
NrIceCtxHandler::RollbackIceRestart()
{
if (old_ctx == nullptr) {
return;
}
current_ctx = old_ctx;
old_ctx = nullptr;
}
NrIceStats NrIceCtxHandler::Destroy()
{
NrIceStats stats;
// designed to be called more than once so if stats are desired, this can be
// called just prior to the destructor
if (old_ctx && current_ctx) {
stats = old_ctx->Destroy();
current_ctx->AccumulateStats(stats);
}
if (current_ctx) {
stats = current_ctx->Destroy();
}
old_ctx = nullptr;
current_ctx = nullptr;
return stats;
}
NrIceCtxHandler::~NrIceCtxHandler()
{
Destroy();
}
} // close namespace

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

@ -1,50 +0,0 @@
#ifndef nricectxhandler_h__
#define nricectxhandler_h__
#include "nricectx.h"
namespace mozilla {
class NrIceCtxHandler {
public:
// TODO(ekr@rtfm.com): Too many bools here. Bug 1193437.
static RefPtr<NrIceCtxHandler> Create(const std::string& name,
bool allow_loopback = false,
bool tcp_enabled = true,
bool allow_link_local = false,
NrIceCtx::Policy policy =
NrIceCtx::ICE_POLICY_ALL);
RefPtr<NrIceMediaStream> CreateStream(const std::string& name,
int components);
// CreateCtx is necessary so we can create and initialize the context
// on main thread, but begin the ice restart mechanics on STS thread
RefPtr<NrIceCtx> CreateCtx() const; // for test
RefPtr<NrIceCtx> CreateCtx(const std::string& ufrag,
const std::string& pwd) const;
RefPtr<NrIceCtx> ctx() { return current_ctx; }
bool BeginIceRestart(RefPtr<NrIceCtx> new_ctx);
bool IsRestarting() const { return (old_ctx != nullptr); }
void FinalizeIceRestart();
void RollbackIceRestart();
NrIceStats Destroy();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceCtxHandler)
private:
NrIceCtxHandler(const std::string& name, NrIceCtx::Policy policy);
NrIceCtxHandler() = delete;
~NrIceCtxHandler();
DISALLOW_COPY_ASSIGN(NrIceCtxHandler);
RefPtr<NrIceCtx> current_ctx;
RefPtr<NrIceCtx> old_ctx; // for while restart is in progress
int restart_count; // used to differentiate streams between restarted ctx
};
} // close namespace
#endif // nricectxhandler_h__

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

@ -183,28 +183,14 @@ static UniquePtr<NrIceCandidate> MakeNrIceCandidate(const nr_ice_candidate& cand
return out;
}
// NrIceMediaStream
RefPtr<NrIceMediaStream>
NrIceMediaStream::Create(NrIceCtx *ctx,
const std::string& name,
int components) {
RefPtr<NrIceMediaStream> stream =
new NrIceMediaStream(ctx, name, components);
MOZ_ASSERT(stream->ctx_ == ctx->ctx());
int r = nr_ice_add_media_stream(ctx->ctx(),
const_cast<char *>(name.c_str()),
components, &stream->stream_);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't create ICE media stream for '"
<< name << "'");
return nullptr;
}
return stream;
static bool Matches(const nr_ice_media_stream* stream,
const std::string& ufrag,
const std::string& pwd) {
return stream && (stream->ufrag == ufrag) && (stream->pwd == pwd);
}
NrIceMediaStream::NrIceMediaStream(NrIceCtx *ctx,
const std::string& id,
const std::string& name,
size_t components) :
state_(ICE_CONNECTING),
@ -213,7 +199,8 @@ NrIceMediaStream::NrIceMediaStream(NrIceCtx *ctx,
name_(name),
components_(components),
stream_(nullptr),
has_parsed_attrs_(false)
old_stream_(nullptr),
id_(id)
{
}
@ -222,35 +209,84 @@ NrIceMediaStream::~NrIceMediaStream() {
// are attached to the ice ctx.
}
nsresult NrIceMediaStream::ParseAttributes(std::vector<std::string>&
attributes) {
if (!stream_)
return NS_ERROR_FAILURE;
nsresult NrIceMediaStream::ConnectToPeer(
const std::string& ufrag,
const std::string& pwd,
const std::vector<std::string>& attributes) {
MOZ_ASSERT(stream_);
std::vector<char *> attributes_in;
attributes_in.reserve(attributes.size());
for (auto& attribute : attributes) {
attributes_in.push_back(const_cast<char *>(attribute.c_str()));
if (Matches(old_stream_, ufrag, pwd)) {
// Roll back to old stream, since we apparently aren't using the new one
// (We swap before we close so we never have stream_ == nullptr)
std::swap(stream_, old_stream_);
CloseStream(&old_stream_);
} else if (old_stream_) {
// Right now we wait for ICE to complete before closing the old stream.
// It might be worth it to close it sooner, but we don't want to close it
// right away.
nr_ice_media_stream_set_obsolete(old_stream_);
}
// Still need to call nr_ice_ctx_parse_stream_attributes.
int r = nr_ice_peer_ctx_parse_stream_attributes(ctx_peer_,
stream_,
attributes_in.empty() ?
nullptr : &attributes_in[0],
attributes_in.size());
nr_ice_media_stream* peer_stream;
if (nr_ice_peer_ctx_find_pstream(ctx_peer_, stream_, &peer_stream)) {
// No peer yet
std::vector<char *> attributes_in;
attributes_in.reserve(attributes.size());
for (auto& attribute : attributes) {
MOZ_MTLOG(ML_DEBUG, "Setting " << attribute << " on stream " << name_);
attributes_in.push_back(const_cast<char *>(attribute.c_str()));
}
// Still need to call nr_ice_ctx_parse_stream_attributes.
int r = nr_ice_peer_ctx_parse_stream_attributes(ctx_peer_,
stream_,
attributes_in.empty() ?
nullptr : &attributes_in[0],
attributes_in.size());
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't parse attributes for stream "
<< name_ << "'");
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
nsresult NrIceMediaStream::SetIceCredentials(const std::string& ufrag,
const std::string& pwd) {
if (Matches(stream_, ufrag, pwd)) {
return NS_OK;
}
MOZ_MTLOG(ML_DEBUG, "Setting ICE credentials for " << name_ << " - "
<< ufrag << ":" << pwd);
CloseStream(&old_stream_);
old_stream_ = stream_;
std::string name(name_ + " - " + ufrag + ":" + pwd);
int r = nr_ice_add_media_stream(ctx_,
name.c_str(),
ufrag.c_str(),
pwd.c_str(),
components_, &stream_);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't parse attributes for stream "
<< name_ << "'");
MOZ_MTLOG(ML_ERROR, "Couldn't create ICE media stream for '"
<< name_ << "': error=" << r);
stream_ = old_stream_;
old_stream_ = nullptr;
return NS_ERROR_FAILURE;
}
has_parsed_attrs_ = true;
state_ = ICE_CONNECTING;
return NS_OK;
}
// Parse trickle ICE candidate
nsresult NrIceMediaStream::ParseTrickleCandidate(const std::string& candidate) {
// TODO(bug 1490658): This needs to take ufrag into account. For now, trickle
// candidates will land on the most recently-created ICE stream.
int r;
MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << ctx_->label << ")/STREAM(" <<
@ -463,7 +499,7 @@ nsresult NrIceMediaStream::GetDefaultCandidate(
return NS_OK;
}
std::vector<std::string> NrIceMediaStream::GetCandidates() const {
std::vector<std::string> NrIceMediaStream::GetAttributes() const {
char **attrs = nullptr;
int attrct;
int r;
@ -587,13 +623,19 @@ nsresult NrIceMediaStream::GetConsentStatus(int component_id, bool *can_send, st
return NS_OK;
}
bool NrIceMediaStream::HasStream(nr_ice_media_stream *stream) const {
return (stream == stream_) || (stream == old_stream_);
}
nsresult NrIceMediaStream::SendPacket(int component_id,
const unsigned char *data,
size_t len) {
if (!stream_)
nr_ice_media_stream* stream = old_stream_ ? old_stream_ : stream_;
if (!stream) {
return NS_ERROR_FAILURE;
}
int r = nr_ice_media_stream_send(ctx_peer_, stream_,
int r = nr_ice_media_stream_send(ctx_peer_, stream,
component_id,
const_cast<unsigned char *>(data), len);
if (r) {
@ -615,6 +657,7 @@ void NrIceMediaStream::Ready() {
if (state_ != ICE_OPEN) {
MOZ_MTLOG(ML_DEBUG, "Marking stream ready '" << name_ << "'");
state_ = ICE_OPEN;
CloseStream(&old_stream_);
SignalReady(this);
}
else {
@ -622,16 +665,34 @@ void NrIceMediaStream::Ready() {
}
}
void NrIceMediaStream::Failed() {
if (state_ != ICE_CLOSED) {
MOZ_MTLOG(ML_DEBUG, "Marking stream failed '" << name_ << "'");
state_ = ICE_CLOSED;
// We don't need the old stream anymore.
CloseStream(&old_stream_);
SignalFailed(this);
}
}
void NrIceMediaStream::Close() {
MOZ_MTLOG(ML_DEBUG, "Marking stream closed '" << name_ << "'");
state_ = ICE_CLOSED;
if (stream_) {
int r = nr_ice_remove_media_stream(ctx_, &stream_);
CloseStream(&old_stream_);
CloseStream(&stream_);
}
void
NrIceMediaStream::CloseStream(nr_ice_media_stream **stream)
{
if (*stream) {
int r = nr_ice_remove_media_stream(ctx_, stream);
if (r) {
MOZ_ASSERT(false, "Failed to remove stream");
MOZ_MTLOG(ML_ERROR, "Failed to remove stream, error=" << r);
}
*stream = nullptr;
}
}

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

@ -137,9 +137,15 @@ struct NrIceCandidatePair {
class NrIceMediaStream {
public:
static RefPtr<NrIceMediaStream> Create(NrIceCtx *ctx,
const std::string& name,
int components);
NrIceMediaStream(NrIceCtx *ctx,
const std::string& id,
const std::string& name,
size_t components);
nsresult SetIceCredentials(const std::string& ufrag, const std::string& pwd);
nsresult ConnectToPeer(const std::string& ufrag,
const std::string& pwd,
const std::vector<std::string>& peer_attrs);
enum State { ICE_CONNECTING, ICE_OPEN, ICE_CLOSED};
State state() const { return state_; }
@ -147,8 +153,8 @@ class NrIceMediaStream {
// The name of the stream
const std::string& name() const { return name_; }
// Get all the candidates
std::vector<std::string> GetCandidates() const;
// Get all the ICE attributes; used for testing
std::vector<std::string> GetAttributes() const;
nsresult GetLocalCandidates(std::vector<NrIceCandidate>* candidates) const;
nsresult GetRemoteCandidates(std::vector<NrIceCandidate>* candidates) const;
@ -159,10 +165,6 @@ class NrIceMediaStream {
nsresult GetDefaultCandidate(int component, NrIceCandidate* candidate) const;
// Parse remote attributes
nsresult ParseAttributes(std::vector<std::string>& candidates);
bool HasParsedAttributes() const { return has_parsed_attrs_; }
// Parse trickle ICE candidate
nsresult ParseTrickleCandidate(const std::string& candidate);
@ -182,8 +184,7 @@ class NrIceMediaStream {
// The number of components
size_t components() const { return components_; }
// The underlying nICEr stream
nr_ice_media_stream *stream() { return stream_; }
bool HasStream(nr_ice_media_stream *stream) const;
// Signals to indicate events. API users can (and should)
// register for these.
@ -192,6 +193,7 @@ class NrIceMediaStream {
// Set your state to ready. Called by the NrIceCtx;
void Ready();
void Failed();
// Close the stream. Called by the NrIceCtx.
// Different from the destructor because other people
@ -201,8 +203,6 @@ class NrIceMediaStream {
// So the receiver of SignalCandidate can determine which transport
// the candidate belongs to.
void SetId(const std::string& id) { id_ = id; }
const std::string& GetId() const { return id_; }
sigslot::signal2<NrIceMediaStream *, const std::string& >
@ -216,22 +216,20 @@ class NrIceMediaStream {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceMediaStream)
private:
NrIceMediaStream(NrIceCtx *ctx,
const std::string& name,
size_t components);
~NrIceMediaStream();
DISALLOW_COPY_ASSIGN(NrIceMediaStream);
void CloseStream(nr_ice_media_stream **stream);
State state_;
nr_ice_ctx *ctx_;
nr_ice_peer_ctx *ctx_peer_;
const std::string name_;
const size_t components_;
nr_ice_media_stream *stream_;
std::string id_;
bool has_parsed_attrs_;
nr_ice_media_stream *old_stream_;
const std::string id_;
};

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

@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "nsIDNSService.h"
#include "nsIDNSListener.h"
#include "nsICancelable.h"
#include "nricectx.h"
typedef struct nr_resolver_ nr_resolver;
typedef struct nr_resolver_vtbl_ nr_resolver_vtbl;

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

@ -23,7 +23,20 @@
#include "nsThreadUtils.h"
#include "nsXPCOM.h"
#include "nricectxhandler.h"
extern "C" {
#include "r_types.h"
#include "async_wait.h"
#include "async_timer.h"
#include "r_data.h"
#include "util.h"
#include "r_time.h"
}
#include "ice_ctx.h"
#include "ice_peer_ctx.h"
#include "ice_media_stream.h"
#include "nricectx.h"
#include "nricemediastream.h"
#include "nriceresolverfake.h"
#include "nriceresolver.h"
@ -38,17 +51,6 @@
#include "stun_socket_filter.h"
#include "mozilla/net/DNS.h"
#include "ice_ctx.h"
#include "ice_peer_ctx.h"
#include "ice_media_stream.h"
extern "C" {
#include "async_timer.h"
#include "r_data.h"
#include "util.h"
#include "r_time.h"
}
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
#include "gtest_utils.h"
@ -380,9 +382,9 @@ class IceTestPeer : public sigslot::has_slots<> {
bool allow_link_local = false,
NrIceCtx::Policy ice_policy = NrIceCtx::ICE_POLICY_ALL) :
name_(name),
ice_ctx_(NrIceCtxHandler::Create(name, allow_loopback,
enable_tcp, allow_link_local,
ice_policy)),
ice_ctx_(NrIceCtx::Create(name, allow_loopback,
enable_tcp, allow_link_local,
ice_policy)),
offerer_(offerer),
candidates_(),
stream_counter_(0),
@ -405,16 +407,16 @@ class IceTestPeer : public sigslot::has_slots<> {
simulate_ice_lite_(false),
nat_(new TestNat),
test_utils_(utils) {
ice_ctx_->ctx()->SignalGatheringStateChange.connect(
ice_ctx_->SignalGatheringStateChange.connect(
this,
&IceTestPeer::GatheringStateChange);
ice_ctx_->ctx()->SignalConnectionStateChange.connect(
ice_ctx_->SignalConnectionStateChange.connect(
this,
&IceTestPeer::ConnectionStateChange);
consent_timestamp_.tv_sec = 0;
consent_timestamp_.tv_usec = 0;
int r = ice_ctx_->ctx()->SetNat(nat_);
int r = ice_ctx_->SetNat(nat_);
(void)r;
MOZ_ASSERT(!r);
}
@ -435,13 +437,28 @@ class IceTestPeer : public sigslot::has_slots<> {
return id;
}
void SetIceCredentials_s(NrIceMediaStream &stream) {
static size_t counter = 0;
std::ostringstream prefix;
prefix << name_ << "-" << counter++;
std::string ufrag = prefix.str() + "-ufrag";
std::string pwd = prefix.str() + "-pwd";
if (mIceCredentials.count(stream.GetId())) {
mOldIceCredentials[stream.GetId()] = mIceCredentials[stream.GetId()];
}
mIceCredentials[stream.GetId()] = std::make_pair(ufrag, pwd);
stream.SetIceCredentials(ufrag, pwd);
}
void AddStream_s(int components) {
std::string id = MakeTransportId(stream_counter_++);
RefPtr<NrIceMediaStream> stream = ice_ctx_->CreateStream(id, components);
ice_ctx_->ctx()->SetStream(id, stream);
RefPtr<NrIceMediaStream> stream =
ice_ctx_->CreateStream(id, id, components);
ASSERT_TRUE(stream);
SetIceCredentials_s(*stream);
stream->SignalCandidate.connect(this, &IceTestPeer::CandidateInitialized);
stream->SignalReady.connect(this, &IceTestPeer::StreamReady);
stream->SignalFailed.connect(this, &IceTestPeer::StreamFailed);
@ -456,7 +473,7 @@ class IceTestPeer : public sigslot::has_slots<> {
}
void RemoveStream_s(size_t index) {
ice_ctx_->ctx()->SetStream(MakeTransportId(index), nullptr);
ice_ctx_->DestroyStream(MakeTransportId(index));
}
void RemoveStream(size_t index) {
@ -467,7 +484,7 @@ class IceTestPeer : public sigslot::has_slots<> {
RefPtr<NrIceMediaStream> GetStream_s(size_t index) {
std::string id = MakeTransportId(index);
return ice_ctx_->ctx()->GetStream(id);
return ice_ctx_->GetStream(id);
}
void SetStunServer(const std::string addr, uint16_t port,
@ -485,7 +502,7 @@ class IceTestPeer : public sigslot::has_slots<> {
}
void SetStunServers(const std::vector<NrIceStunServer> &servers) {
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->ctx()->SetStunServers(servers)));
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(servers)));
}
void UseTestStunServer() {
@ -510,11 +527,11 @@ class IceTestPeer : public sigslot::has_slots<> {
UniquePtr<NrIceTurnServer> server(NrIceTurnServer::Create(
addr, port, username, password, transport));
turn_servers.push_back(*server);
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->ctx()->SetTurnServers(turn_servers)));
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(turn_servers)));
}
void SetTurnServers(const std::vector<NrIceTurnServer> servers) {
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->ctx()->SetTurnServers(servers)));
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(servers)));
}
void SetFakeResolver(const std::string& ip,
@ -527,13 +544,13 @@ class IceTestPeer : public sigslot::has_slots<> {
ASSERT_EQ(PR_SUCCESS, status);
fake_resolver_.SetAddr(fqdn, addr);
}
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->ctx()->SetResolver(
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
fake_resolver_.AllocateResolver())));
}
void SetDNSResolver() {
ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->ctx()->SetResolver(
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
dns_resolver_->AllocateResolver())));
}
@ -542,7 +559,7 @@ class IceTestPeer : public sigslot::has_slots<> {
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res,
ice_ctx_->ctx(),
ice_ctx_,
&NrIceCtx::StartGathering,
default_route_only,
false),
@ -556,7 +573,7 @@ class IceTestPeer : public sigslot::has_slots<> {
}
void SetTimerDivider(int div) {
ice_ctx_->ctx()->internal_SetTimerAccelarator(div);
ice_ctx_->internal_SetTimerAccelarator(div);
}
void SetStunResponseDelay(uint32_t delay) {
@ -584,19 +601,19 @@ class IceTestPeer : public sigslot::has_slots<> {
// Get various pieces of state
std::vector<std::string> GetGlobalAttributes() {
std::vector<std::string> attrs(ice_ctx_->ctx()->GetGlobalAttributes());
std::vector<std::string> attrs(ice_ctx_->GetGlobalAttributes());
if (simulate_ice_lite_) {
attrs.push_back("ice-lite");
}
return attrs;
}
std::vector<std::string> GetCandidates(size_t stream) {
std::vector<std::string> GetAttributes(size_t stream) {
std::vector<std::string> v;
RUN_ON_THREAD(
test_utils_->sts_target(),
WrapRunnableRet(&v, this, &IceTestPeer::GetCandidates_s, stream));
WrapRunnableRet(&v, this, &IceTestPeer::GetAttributes_s, stream));
return v;
}
@ -608,27 +625,31 @@ class IceTestPeer : public sigslot::has_slots<> {
return candidate;
}
std::vector<std::string> GetCandidates_s(size_t index) {
std::vector<std::string> candidates;
std::vector<std::string> GetAttributes_s(size_t index) {
std::vector<std::string> attributes;
auto stream = GetStream_s(index);
if (!stream) {
EXPECT_TRUE(false) << "No such stream " << index;
return candidates;
return attributes;
}
std::vector<std::string> candidates_in = stream->GetCandidates();
std::vector<std::string> attributes_in = stream->GetAttributes();
for (const auto& a_candidate : candidates_in) {
std::string candidate(FilterCandidate(a_candidate));
if (!candidate.empty()) {
std::cerr << name_ << " Returning candidate: "
<< candidate << std::endl;
candidates.push_back(candidate);
for (const auto& attribute : attributes_in) {
if (attribute.find("candidate:") != std::string::npos) {
std::string candidate(FilterCandidate(attribute));
if (!candidate.empty()) {
std::cerr << name_ << " Returning candidate: "
<< candidate << std::endl;
attributes.push_back(candidate);
}
} else {
attributes.push_back(attribute);
}
}
return candidates;
return attributes;
}
void SetExpectedTypes(NrIceCandidate::Type local,
@ -644,13 +665,13 @@ class IceTestPeer : public sigslot::has_slots<> {
}
int GetCandidatesPrivateIpv4Range(size_t stream) {
std::vector<std::string> candidates = GetCandidates(stream);
std::vector<std::string> attributes = GetAttributes(stream);
int host_net = 0;
for (const auto& c : candidates) {
if (c.find("typ host") != std::string::npos) {
for (const auto& a : attributes) {
if (a.find("typ host") != std::string::npos) {
nr_transport_addr addr;
std::vector<std::string> tokens = split(c, ' ');
std::vector<std::string> tokens = split(a, ' ');
int r = nr_str_port_to_transport_addr(tokens.at(4).c_str(), 0, IPPROTO_UDP, &addr);
MOZ_ASSERT(!r);
if (!r && (addr.ip_version == NR_IPV4)) {
@ -697,23 +718,15 @@ class IceTestPeer : public sigslot::has_slots<> {
void RestartIce() {
test_utils_->sts_target()->Dispatch(
WrapRunnable(this,
&IceTestPeer::RestartIce_s,
ice_ctx_->CreateCtx()),
&IceTestPeer::RestartIce_s),
NS_DISPATCH_SYNC);
}
void RestartIce_s(RefPtr<NrIceCtx> new_ctx) {
ice_ctx_->BeginIceRestart(new_ctx);
// set signals for the newly restarted ctx
ice_ctx_->ctx()->SignalGatheringStateChange.connect(
this,
&IceTestPeer::GatheringStateChange);
ice_ctx_->ctx()->SignalConnectionStateChange.connect(
this,
&IceTestPeer::ConnectionStateChange);
void RestartIce_s() {
for (auto& stream : ice_ctx_->GetStreams()) {
SetIceCredentials_s(*stream);
}
// take care of some local bookkeeping
ready_ct_ = 0;
gathering_complete_ = false;
@ -721,19 +734,6 @@ class IceTestPeer : public sigslot::has_slots<> {
ice_failed_ = false;
ice_reached_checking_ = false;
remote_ = nullptr;
stream_counter_ = 0;
}
void FinalizeIceRestart() {
test_utils_->sts_target()->Dispatch(
WrapRunnable(this, &IceTestPeer::FinalizeIceRestart_s),
NS_DISPATCH_SYNC);
}
void FinalizeIceRestart_s() {
ice_ctx_->FinalizeIceRestart();
}
@ -745,7 +745,9 @@ class IceTestPeer : public sigslot::has_slots<> {
void RollbackIceRestart_s() {
ice_ctx_->RollbackIceRestart();
for (auto& stream : ice_ctx_->GetStreams()) {
mIceCredentials[stream->GetId()] = mOldIceCredentials[stream->GetId()];
}
}
@ -760,44 +762,38 @@ class IceTestPeer : public sigslot::has_slots<> {
ice_connected_ = false;
ice_failed_ = false;
ice_reached_checking_ = false;
res = ice_ctx_->ctx()->ParseGlobalAttributes(remote->GetGlobalAttributes());
res = ice_ctx_->ParseGlobalAttributes(remote->GetGlobalAttributes());
ASSERT_TRUE(NS_SUCCEEDED(res));
if (trickle_mode == TRICKLE_NONE ||
trickle_mode == TRICKLE_REAL) {
for (size_t i=0; i<stream_counter_; ++i) {
auto aStream = GetStream_s(i);
if (!aStream || aStream->HasParsedAttributes()) {
continue;
}
std::vector<std::string> candidates =
remote->GetCandidates(i);
for (size_t i=0; i<stream_counter_; ++i) {
auto aStream = GetStream_s(i);
if (aStream) {
std::vector<std::string> attributes = remote->GetAttributes(i);
for (const auto& candidate : candidates) {
std::cerr << name_ << " Adding remote candidate: " + candidate << std::endl;
for (auto it = attributes.begin(); it != attributes.end();) {
if (trickle_mode == TRICKLE_SIMULATE &&
it->find("candidate:") != std::string::npos) {
std::cerr << name_ << " Deferring remote candidate: " << *it
<< std::endl;
attributes.erase(it);
} else {
std::cerr << name_ << " Adding remote attribute: " + *it
<< std::endl;
++it;
}
}
res = aStream->ParseAttributes(candidates);
ASSERT_TRUE(NS_SUCCEEDED(res));
}
} else {
// Parse empty attributes and then trickle them out later
for (size_t i=0; i<stream_counter_; ++i) {
auto aStream = GetStream_s(i);
if (!aStream || aStream->HasParsedAttributes()) {
continue;
}
std::vector<std::string> empty_attrs;
std::cout << "Calling ParseAttributes on stream " << i << std::endl;
res = aStream->ParseAttributes(empty_attrs);
auto credentials = mIceCredentials[aStream->GetId()];
res = aStream->ConnectToPeer(
credentials.first, credentials.second, attributes);
ASSERT_TRUE(NS_SUCCEEDED(res));
}
}
if (start) {
ice_ctx_->ctx()->SetControlling(
ice_ctx_->SetControlling(
offerer_ ? NrIceCtx::ICE_CONTROLLING : NrIceCtx::ICE_CONTROLLED);
// Now start checks
res = ice_ctx_->ctx()->StartChecks(offerer_);
res = ice_ctx_->StartChecks(offerer_);
ASSERT_TRUE(NS_SUCCEEDED(res));
}
}
@ -829,13 +825,14 @@ class IceTestPeer : public sigslot::has_slots<> {
std::vector<SchedulableTrickleCandidate*>& ControlTrickle(size_t stream) {
std::cerr << "Doing controlled trickle for stream " << stream << std::endl;
std::vector<std::string> candidates =
remote_->GetCandidates(stream);
std::vector<std::string> attributes = remote_->GetAttributes(stream);
for (const auto& candidate : candidates) {
controlled_trickle_candidates_[stream].push_back(
new SchedulableTrickleCandidate(
this, stream, candidate, test_utils_));
for (const auto& attribute : attributes) {
if (attribute.find("candidate:") != std::string::npos) {
controlled_trickle_candidates_[stream].push_back(
new SchedulableTrickleCandidate(
this, stream, attribute, test_utils_));
}
}
return controlled_trickle_candidates_[stream];
@ -919,7 +916,7 @@ class IceTestPeer : public sigslot::has_slots<> {
void DumpAndCheckActiveCandidates_s() {
std::cerr << name_ << " Active candidates:" << std::endl;
for (const auto& stream : ice_ctx_->ctx()->GetStreams()) {
for (const auto& stream : ice_ctx_->GetStreams()) {
for (size_t j=0; j < stream->components(); ++j) {
std::cerr << name_ << " Stream " << stream->GetId()
<< " component " << j+1 << std::endl;
@ -969,7 +966,7 @@ class IceTestPeer : public sigslot::has_slots<> {
void Close() {
test_utils_->sts_target()->Dispatch(
WrapRunnable(ice_ctx_->ctx(), &NrIceCtx::destroy_peer_ctx),
WrapRunnable(ice_ctx_, &NrIceCtx::destroy_peer_ctx),
NS_DISPATCH_SYNC);
}
@ -999,13 +996,13 @@ class IceTestPeer : public sigslot::has_slots<> {
nsresult res;
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res, ice_ctx_->ctx(), &NrIceCtx::SetControlling,
WrapRunnableRet(&res, ice_ctx_, &NrIceCtx::SetControlling,
offerer_ ?
NrIceCtx::ICE_CONTROLLING : NrIceCtx::ICE_CONTROLLED),
NS_DISPATCH_SYNC);
// Now start checks
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res, ice_ctx_->ctx(), &NrIceCtx::StartChecks,
WrapRunnableRet(&res, ice_ctx_, &NrIceCtx::StartChecks,
offerer_),
NS_DISPATCH_SYNC);
ASSERT_TRUE(NS_SUCCEEDED(res));
@ -1024,14 +1021,14 @@ class IceTestPeer : public sigslot::has_slots<> {
std::cerr << name_ << " Gathering complete" << std::endl;
gathering_complete_ = true;
std::cerr << name_ << " CANDIDATES:" << std::endl;
for (const auto& stream : ice_ctx_->ctx()->GetStreams()) {
std::cerr << name_ << " ATTRIBUTES:" << std::endl;
for (const auto& stream : ice_ctx_->GetStreams()) {
std::cerr << "Stream " << stream->GetId() << std::endl;
std::vector<std::string> candidates = stream->GetCandidates();
std::vector<std::string> attributes = stream->GetAttributes();
for(const auto& candidate : candidates) {
std::cerr << candidate << std::endl;
for(const auto& attribute : attributes) {
std::cerr << attribute << std::endl;
}
}
std::cerr << std::endl;
@ -1116,7 +1113,7 @@ class IceTestPeer : public sigslot::has_slots<> {
void DumpCandidatePairs_s() {
std::cerr << "Dumping candidate pairs for all streams [" << std::endl;
for (const auto& stream : ice_ctx_->ctx()->GetStreams()) {
for (const auto& stream : ice_ctx_->GetStreams()) {
DumpCandidatePairs_s(stream.get());
}
std::cerr << "]" << std::endl;
@ -1281,11 +1278,7 @@ class IceTestPeer : public sigslot::has_slots<> {
void ParseCandidate_s(size_t i, const std::string& candidate) {
auto media_stream = GetStream_s(i);
ASSERT_TRUE(media_stream.get()) << "No such stream " << i;
std::vector<std::string> attributes;
attributes.push_back(candidate);
media_stream->ParseAttributes(attributes);
media_stream->ParseTrickleCandidate(candidate);
}
void ParseCandidate(size_t i, const std::string& candidate)
@ -1355,7 +1348,7 @@ class IceTestPeer : public sigslot::has_slots<> {
}
void ChangeNetworkState_s(bool online) {
ice_ctx_->ctx()->UpdateNetworkState(online);
ice_ctx_->UpdateNetworkState(online);
}
void ChangeNetworkStateToOffline() {
@ -1377,7 +1370,7 @@ class IceTestPeer : public sigslot::has_slots<> {
void SetControlling(NrIceCtx::Controlling controlling) {
nsresult res;
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res, ice_ctx_->ctx(),
WrapRunnableRet(&res, ice_ctx_,
&NrIceCtx::SetControlling,
controlling),
NS_DISPATCH_SYNC);
@ -1385,7 +1378,7 @@ class IceTestPeer : public sigslot::has_slots<> {
}
NrIceCtx::Controlling GetControlling() {
return ice_ctx_->ctx()->GetControlling();
return ice_ctx_->GetControlling();
}
void SetTiebreaker(uint64_t tiebreaker) {
@ -1397,7 +1390,7 @@ class IceTestPeer : public sigslot::has_slots<> {
}
void SetTiebreaker_s(uint64_t tiebreaker) {
ice_ctx_->ctx()->peer()->tiebreaker = tiebreaker;
ice_ctx_->peer()->tiebreaker = tiebreaker;
}
void SimulateIceLite() {
@ -1423,12 +1416,14 @@ class IceTestPeer : public sigslot::has_slots<> {
private:
std::string name_;
RefPtr<NrIceCtxHandler> ice_ctx_;
RefPtr<NrIceCtx> ice_ctx_;
bool offerer_;
std::map<std::string, std::vector<std::string> > candidates_;
// Maps from stream id to list of remote trickle candidates
std::map<size_t, std::vector<SchedulableTrickleCandidate*> >
controlled_trickle_candidates_;
std::map<std::string, std::pair<std::string, std::string>> mIceCredentials;
std::map<std::string, std::pair<std::string, std::string>> mOldIceCredentials;
size_t stream_counter_;
bool shutting_down_;
bool gathering_complete_;
@ -1598,11 +1593,11 @@ class WebRtcIceGatherTest : public StunTest {
bool StreamHasMatchingCandidate(unsigned int stream,
const std::string& match,
const std::string& match2 = "") {
std::vector<std::string> candidates = peer_->GetCandidates(stream);
for (auto& candidate : candidates) {
if (std::string::npos != candidate.find(match)) {
std::vector<std::string> attributes = peer_->GetAttributes(stream);
for (auto& attribute : attributes) {
if (std::string::npos != attribute.find(match)) {
if (!match2.length() ||
std::string::npos != candidate.find(match2)) {
std::string::npos != attribute.find(match2)) {
return true;
}
}
@ -1610,14 +1605,14 @@ class WebRtcIceGatherTest : public StunTest {
return false;
}
void DumpCandidates(unsigned int stream) {
std::vector<std::string> candidates = peer_->GetCandidates(stream);
void DumpAttributes(unsigned int stream) {
std::vector<std::string> attributes = peer_->GetAttributes(stream);
std::cerr << "Candidates for stream " << stream << "->"
<< candidates.size() << std::endl;
std::cerr << "Attributes for stream " << stream << "->"
<< attributes.size() << std::endl;
for (const auto& c : candidates) {
std::cerr << "Candidate: " << c << std::endl;
for (const auto& a : attributes) {
std::cerr << "Attribute: " << a << std::endl;
}
}
@ -1812,7 +1807,9 @@ class WebRtcIceConnectTest : public StunTest {
ConnectCallerAndCallee(p1_.get(), p2_.get());
}
void ConnectCallerAndCallee(IceTestPeer* caller, IceTestPeer* callee) {
void ConnectCallerAndCallee(IceTestPeer* caller,
IceTestPeer* callee,
TrickleMode mode = TRICKLE_NONE) {
ASSERT_TRUE(caller->ready_ct() == 0);
ASSERT_TRUE(caller->ice_connected() == 0);
ASSERT_TRUE(caller->ice_reached_checking() == 0);
@ -1824,19 +1821,20 @@ class WebRtcIceConnectTest : public StunTest {
// gives them to |this|, meaning that callee->Connect(caller, ...)
// simulates caller sending an offer to callee. Order matters here
// because it determines which peer is controlling.
callee->Connect(caller, TRICKLE_NONE);
caller->Connect(callee, TRICKLE_NONE);
callee->Connect(caller, mode);
caller->Connect(callee, mode);
ASSERT_TRUE_WAIT(caller->ready_ct() == 1 && callee->ready_ct() == 1,
kDefaultTimeout);
ASSERT_TRUE_WAIT(caller->ice_connected() && callee->ice_connected(),
kDefaultTimeout);
if (mode != TRICKLE_SIMULATE) {
ASSERT_TRUE_WAIT(caller->ready_ct() == 1 && callee->ready_ct() == 1,
kDefaultTimeout);
ASSERT_TRUE_WAIT(caller->ice_connected() && callee->ice_connected(),
kDefaultTimeout);
ASSERT_TRUE(caller->ice_reached_checking());
ASSERT_TRUE(callee->ice_reached_checking());
ASSERT_TRUE(caller->ice_reached_checking());
ASSERT_TRUE(callee->ice_reached_checking());
caller->DumpAndCheckActiveCandidates();
callee->DumpAndCheckActiveCandidates();
caller->DumpAndCheckActiveCandidates();
callee->DumpAndCheckActiveCandidates();
}
}
void SetExpectedTypes(NrIceCandidate::Type local, NrIceCandidate::Type remote,
@ -1941,15 +1939,18 @@ class WebRtcIceConnectTest : public StunTest {
size_t previousSent = p1->sent();
size_t previousReceived = p2->received();
test_utils_->sts_target()->Dispatch(
WrapRunnable(p1,
&IceTestPeer::SendPacket, 0, 1,
reinterpret_cast<const unsigned char *>("TEST"), 4),
NS_DISPATCH_SYNC);
if (expect_tx_failure) {
test_utils_->sts_target()->Dispatch(
WrapRunnable(p1, &IceTestPeer::SendFailure, 0, 1),
NS_DISPATCH_SYNC);
ASSERT_EQ(previousSent, p1->sent());
} else {
test_utils_->sts_target()->Dispatch(
WrapRunnable(p1,
&IceTestPeer::SendPacket, 0, 1,
reinterpret_cast<const unsigned char *>("TEST"), 4),
NS_DISPATCH_SYNC);
ASSERT_EQ(previousSent+1, p1->sent());
}
if (expect_rx_failure) {
@ -2036,7 +2037,7 @@ class WebRtcIcePacketFilterTest : public StunTest {
StunTest::SetUp();
// Set up enough of the ICE ctx to allow the packet filter to work
ice_ctx_ = NrIceCtxHandler::Create("test", true);
ice_ctx_ = NrIceCtx::Create("test", true);
nsCOMPtr<nsISocketFilterHandler> udp_handler =
do_GetService(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID);
@ -2148,7 +2149,7 @@ class WebRtcIcePacketFilterTest : public StunTest {
nsCOMPtr<nsISocketFilter> udp_filter_;
nsCOMPtr<nsISocketFilter> tcp_filter_;
RefPtr<NrIceCtxHandler> ice_ctx_;
RefPtr<NrIceCtx> ice_ctx_;
};
} // end namespace
@ -2363,12 +2364,13 @@ TEST_F(WebRtcIceGatherTest, TestGatherDisableComponent) {
peer_->AddStream(2);
peer_->DisableComponent(1, 2);
Gather();
std::vector<std::string> candidates =
peer_->GetCandidates(1);
std::vector<std::string> attributes = peer_->GetAttributes(1);
for (auto& candidate : candidates) {
size_t sp1 = candidate.find(' ');
ASSERT_EQ(0, candidate.compare(sp1+1, 1, "1", 1));
for (auto& attribute : attributes) {
if (attribute.find("candidate:") != std::string::npos) {
size_t sp1 = attribute.find(' ');
ASSERT_EQ(0, attribute.compare(sp1+1, 1, "1", 1));
}
}
}
@ -2494,7 +2496,7 @@ TEST_F(WebRtcIceGatherTest, TestFakeStunServerNatedNoHost) {
UseFakeStunUdpServerWithResponse("192.0.2.1", 3333);
Gather(0);
WaitForGather();
DumpCandidates(0);
DumpAttributes(0);
ASSERT_FALSE(StreamHasMatchingCandidate(0, "host"));
ASSERT_TRUE(StreamHasMatchingCandidate(0, "srflx"));
NrIceCandidate default_candidate;
@ -2511,7 +2513,7 @@ TEST_F(WebRtcIceGatherTest, TestFakeStunServerNoNatNoHost) {
UseTestStunServer();
Gather(0);
WaitForGather();
DumpCandidates(0);
DumpAttributes(0);
ASSERT_FALSE(StreamHasMatchingCandidate(0, "host"));
ASSERT_TRUE(StreamHasMatchingCandidate(0, "srflx"));
}
@ -2601,17 +2603,15 @@ TEST_F(WebRtcIceConnectTest, TestConnectRestartIce) {
InitPeer(p3_.get());
p3_->AddStream(1);
p2_->AddStream(1);
ASSERT_TRUE(GatherCallerAndCallee(p2_.get(), p3_.get()));
std::cout << "-------------------------------------------------" << std::endl;
ConnectCallerAndCallee(p3_.get(), p2_.get());
SendReceive(p1_.get(), p2_.get()); // p1 and p2 still connected
SendReceive(p3_.get(), p2_.get()); // p3 and p2 are now connected
p2_->FinalizeIceRestart();
SendReceive(p3_.get(), p2_.get()); // p3 and p2 are still connected
ConnectCallerAndCallee(p3_.get(), p2_.get(), TRICKLE_SIMULATE);
SendReceive(p1_.get(), p2_.get()); // p1 and p2 are still connected
SendReceive(p3_.get(), p2_.get(), true, true); // p3 and p2 not yet connected
p2_->SimulateTrickle(0);
p3_->SimulateTrickle(0);
SendReceive(p1_.get(), p2_.get(), false, true); // p1 and p2 not connected
SendReceive(p3_.get(), p2_.get()); // p3 and p2 are now connected
p3_ = nullptr;
}
@ -2633,22 +2633,15 @@ TEST_F(WebRtcIceConnectTest, TestConnectRestartIceThenAbort) {
InitPeer(p3_.get());
p3_->AddStream(1);
p2_->AddStream(1);
ASSERT_TRUE(GatherCallerAndCallee(p2_.get(), p3_.get()));
std::cout << "-------------------------------------------------" << std::endl;
ConnectCallerAndCallee(p3_.get(), p2_.get());
SendReceive(p1_.get(), p2_.get()); // p1 and p2 still connected
SendReceive(p3_.get(), p2_.get()); // p3 and p2 are now connected
p2_->RollbackIceRestart();
SendReceive(p1_.get(), p2_.get()); // p1 and p2 are still connected
SendReceive(p3_.get(), p2_.get(), false, true); // p3 and p2 not connected
p2_->Connect(p1_.get(), TRICKLE_NONE);
SendReceive(p1_.get(), p2_.get());
p3_ = nullptr;
}
TEST_F(WebRtcIceConnectTest, TestConnectSetControllingAfterIceRestart) {
TEST_F(WebRtcIceConnectTest, TestConnectIceRestartRoleConflict) {
AddStream(1);
ASSERT_TRUE(Gather());
// Just for fun lets do this with switched rolls
@ -2662,35 +2655,31 @@ TEST_F(WebRtcIceConnectTest, TestConnectSetControllingAfterIceRestart) {
p2_->RestartIce();
ASSERT_FALSE(p2_->gathering_complete());
// ICE restart should allow us to set control role again
p2_->SetControlling(NrIceCtx::ICE_CONTROLLED);
ASSERT_EQ(NrIceCtx::ICE_CONTROLLED, p2_->GetControlling());
// But still only allowed to set control role once
p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
ASSERT_EQ(NrIceCtx::ICE_CONTROLLED, p2_->GetControlling());
ASSERT_EQ(NrIceCtx::ICE_CONTROLLING, p2_->GetControlling()) <<
"ICE restart should not allow role to change, unless ice-lite happens";
mozilla::UniquePtr<IceTestPeer> p3_;
p3_ = MakeUnique<IceTestPeer>("P3", test_utils_, true, false, false, false);
InitPeer(p3_.get());
p3_->AddStream(1);
// Set control role for p3 accordingly (w/o role conflict)
// Set control role for p3 accordingly (with role conflict)
p3_->SetControlling(NrIceCtx::ICE_CONTROLLING);
ASSERT_EQ(NrIceCtx::ICE_CONTROLLING, p3_->GetControlling());
p2_->AddStream(1);
ASSERT_TRUE(GatherCallerAndCallee(p2_.get(), p3_.get()));
std::cout << "-------------------------------------------------" << std::endl;
ConnectCallerAndCallee(p3_.get(), p2_.get());
// Again connecting should not result in role switch
ASSERT_EQ(NrIceCtx::ICE_CONTROLLED, p2_->GetControlling());
ASSERT_EQ(NrIceCtx::ICE_CONTROLLING, p3_->GetControlling());
auto p2role = p2_->GetControlling();
ASSERT_NE(p2role, p3_->GetControlling()) << "Conflict should be resolved";
ASSERT_EQ(NrIceCtx::ICE_CONTROLLED, p1_->GetControlling())
<< "P1 should be unaffected by role conflict";
p2_->FinalizeIceRestart();
// And again we are not allowed to switch roles at this point any more
p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
ASSERT_EQ(NrIceCtx::ICE_CONTROLLED, p2_->GetControlling());
p3_->SetControlling(NrIceCtx::ICE_CONTROLLED);
ASSERT_EQ(NrIceCtx::ICE_CONTROLLING, p3_->GetControlling());
p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
ASSERT_EQ(NrIceCtx::ICE_CONTROLLED, p1_->GetControlling());
p3_->SetControlling(p2role);
ASSERT_NE(p2role, p3_->GetControlling());
p3_ = nullptr;
}

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

@ -24,7 +24,7 @@ extern "C" {
#include "stunserver.h"
#include "nricectxhandler.h"
#include "nricectx.h"
#include "nricemediastream.h"
#define GTEST_HAS_RTTI 0
@ -47,7 +47,7 @@ class MultiTcpSocketTest : public MtransportTest {
void SetUp() {
MtransportTest::SetUp();
ice_ctx_ = NrIceCtxHandler::Create("stun", true);
ice_ctx_ = NrIceCtx::Create("stun", true);
test_utils_->sts_target()->Dispatch(
WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET),
@ -108,7 +108,7 @@ class MultiTcpSocketTest : public MtransportTest {
stun_server_addr, stun_server_port, kNrIceTransportTcp));
stun_servers.push_back(*server);
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->ctx()->SetStunServers(stun_servers)));
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
}
r = 1;
@ -117,7 +117,7 @@ class MultiTcpSocketTest : public MtransportTest {
(char *)"127.0.0.1", EnsureEphemeral(port_s++), IPPROTO_TCP, &local);
ASSERT_EQ(0, r);
r = nr_socket_multi_tcp_create(ice_ctx_->ctx()->ctx(),
r = nr_socket_multi_tcp_create(ice_ctx_->ctx(),
&local, tcp_type, 1, 2048, sock);
}
@ -347,7 +347,7 @@ class MultiTcpSocketTest : public MtransportTest {
}
std::vector<nr_socket *> socks;
Atomic<bool> readable;
RefPtr<NrIceCtxHandler> ice_ctx_;
RefPtr<NrIceCtx> ice_ctx_;
};
}

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

@ -104,7 +104,10 @@ public:
nr_ice_add_media_stream(ice_ctx_,
const_cast<char *>(name_.c_str()),
"ufrag",
"pass",
2, &ice_media_stream_);
EXPECT_EQ(2UL, GetStreamAttributes().size());
nr_ice_media_stream_initialize(ice_ctx_, ice_media_stream_);
}
@ -144,30 +147,46 @@ public:
ASSERT_TRUE(r == 0 || r == R_WOULDBLOCK);
}
std::vector<std::string> GetLocalCandidates() const {
char attr[256];
std::vector<std::string> candidates;
nr_ice_component* comp = STAILQ_FIRST(&ice_media_stream_->components);
while(comp){
if (comp->state != NR_ICE_COMPONENT_DISABLED) {
nr_ice_candidate *cand = TAILQ_FIRST(&comp->candidates);
while(cand){
int r = nr_ice_format_candidate_attribute(cand, attr, 255);
if (r == 0) {
candidates.push_back(attr);
}
std::vector<std::string> GetStreamAttributes() {
std::vector<std::string> attributes;
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&attributes,
this,
&IcePeer::GetStreamAttributes_s),
NS_DISPATCH_SYNC);
return attributes;
}
cand = TAILQ_NEXT(cand, entry_comp);
}
}
std::vector<std::string> GetStreamAttributes_s() {
comp = STAILQ_NEXT(comp, entry);
char **attrs = nullptr;
int attrct;
std::vector<std::string> ret;
int r =
nr_ice_media_stream_get_attributes(ice_media_stream_, &attrs, &attrct);
EXPECT_EQ(0, r);
for (int i=0; i<attrct; i++) {
ret.push_back(std::string(attrs[i]));
RFREE(attrs[i]);
}
RFREE(attrs);
return candidates;
return ret;
}
std::vector<std::string> GetGlobalAttributes() {
std::vector<std::string> attributes;
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&attributes,
this,
&IcePeer::GetGlobalAttributes_s),
NS_DISPATCH_SYNC);
return attributes;
}
std::vector<std::string> GetGlobalAttributes_s() {
char **attrs = nullptr;
int attrct;
@ -203,6 +222,14 @@ public:
}
void SetRemoteAttributes(std::vector<std::string> attributes) {
test_utils_->sts_target()->Dispatch(
WrapRunnable(this,
&IcePeer::SetRemoteAttributes_s,
attributes),
NS_DISPATCH_SYNC);
}
void SetRemoteAttributes_s(std::vector<std::string> attributes) {
int r;
std::vector<char*> attrs;
@ -329,11 +356,11 @@ TEST_F(TestNrSocketIceUnitTest, TestIcePeer) {
ASSERT_NE(peer.ice_ctx_, nullptr);
ASSERT_NE(peer.peer_ctx_, nullptr);
ASSERT_NE(peer.ice_media_stream_, nullptr);
ASSERT_EQ(2UL, peer.GetStreamAttributes().size())
<< "Should have ice-ufrag and ice-pwd";
peer.Gather();
std::vector<std::string> attrs = peer.GetGlobalAttributes();
ASSERT_NE(attrs.size(), 0UL);
std::vector<std::string> candidates = peer.GetLocalCandidates();
ASSERT_NE(candidates.size(), 0UL);
ASSERT_LT(2UL, peer.GetStreamAttributes().size())
<< "Should have ice-ufrag, ice-pwd, and at least one candidate.";
}
TEST_F(TestNrSocketIceUnitTest, TestIcePeersNoNAT) {
@ -348,13 +375,13 @@ TEST_F(TestNrSocketIceUnitTest, TestIcePeersNoNAT) {
peer2.Gather();
std::vector<std::string> attrs = peer.GetGlobalAttributes();
peer2.ParseGlobalAttributes(attrs);
std::vector<std::string> candidates = peer.GetLocalCandidates();
peer2.SetRemoteAttributes(candidates);
std::vector<std::string> attributes = peer.GetStreamAttributes();
peer2.SetRemoteAttributes(attributes);
attrs = peer2.GetGlobalAttributes();
peer.ParseGlobalAttributes(attrs);
candidates = peer2.GetLocalCandidates();
peer.SetRemoteAttributes(candidates);
attributes = peer2.GetStreamAttributes();
peer.SetRemoteAttributes(attributes);
peer2.StartChecks();
peer.StartChecks();
@ -406,13 +433,13 @@ TEST_F(TestNrSocketIceUnitTest, TestIcePeersPacketLoss) {
peer2.Gather();
std::vector<std::string> attrs = peer.GetGlobalAttributes();
peer2.ParseGlobalAttributes(attrs);
std::vector<std::string> candidates = peer.GetLocalCandidates();
peer2.SetRemoteAttributes(candidates);
std::vector<std::string> attributes = peer.GetStreamAttributes();
peer2.SetRemoteAttributes(attributes);
attrs = peer2.GetGlobalAttributes();
peer.ParseGlobalAttributes(attrs);
candidates = peer2.GetLocalCandidates();
peer.SetRemoteAttributes(candidates);
attributes = peer2.GetStreamAttributes();
peer.SetRemoteAttributes(attributes);
peer2.StartChecks();
peer.StartChecks();

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

@ -26,7 +26,7 @@
#include "mediapacket.h"
#include "dtlsidentity.h"
#include "nricectxhandler.h"
#include "nricectx.h"
#include "nricemediastream.h"
#include "transportflow.h"
#include "transportlayer.h"
@ -443,8 +443,8 @@ class TransportTestPeer : public sigslot::has_slots<> {
lossy_(new TransportLayerLossy()),
dtls_(new TransportLayerDtls()),
identity_(DtlsIdentity::Generate()),
ice_ctx_(NrIceCtxHandler::Create(name)),
streams_(), candidates_(),
ice_ctx_(NrIceCtx::Create(name)),
streams_(),
peer_(nullptr),
gathering_complete_(false),
enabled_cipersuites_(),
@ -454,7 +454,7 @@ class TransportTestPeer : public sigslot::has_slots<> {
UniquePtr<NrIceStunServer> server(NrIceStunServer::Create(
std::string((char *)"stun.services.mozilla.com"), 3478));
stun_servers.push_back(*server);
EXPECT_TRUE(NS_SUCCEEDED(ice_ctx_->ctx()->SetStunServers(stun_servers)));
EXPECT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
dtls_->SetIdentity(identity_);
dtls_->SetRole(offerer_ ?
@ -610,7 +610,7 @@ class TransportTestPeer : public sigslot::has_slots<> {
nsresult res;
// Attach our slots
ice_ctx_->ctx()->SignalGatheringStateChange.
ice_ctx_->SignalGatheringStateChange.
connect(this, &TransportTestPeer::GatheringStateChange);
char name[100];
@ -618,11 +618,10 @@ class TransportTestPeer : public sigslot::has_slots<> {
(int)streams_.size());
// Create the media stream
RefPtr<NrIceMediaStream> stream =
ice_ctx_->CreateStream(static_cast<char *>(name), 1);
RefPtr<NrIceMediaStream> stream = ice_ctx_->CreateStream(name, name, 1);
ASSERT_TRUE(stream != nullptr);
ice_ctx_->ctx()->SetStream(name, stream);
stream->SetIceCredentials("ufrag", "pass");
streams_.push_back(stream);
// Listen for candidates
@ -646,7 +645,7 @@ class TransportTestPeer : public sigslot::has_slots<> {
// Start gathering
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res,
ice_ctx_->ctx(),
ice_ctx_,
&NrIceCtx::StartGathering,
false,
false),
@ -665,7 +664,6 @@ class TransportTestPeer : public sigslot::has_slots<> {
// New candidate
void GotCandidate(NrIceMediaStream *stream, const std::string &candidate) {
std::cerr << "Got candidate " << candidate << std::endl;
candidates_[stream->name()].push_back(candidate);
}
void GatheringStateChange(NrIceCtx* ctx,
@ -689,23 +687,23 @@ class TransportTestPeer : public sigslot::has_slots<> {
// First send attributes
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res, peer_->ice_ctx_->ctx(),
WrapRunnableRet(&res, peer_->ice_ctx_,
&NrIceCtx::ParseGlobalAttributes,
ice_ctx_->ctx()->GetGlobalAttributes()),
ice_ctx_->GetGlobalAttributes()),
NS_DISPATCH_SYNC);
ASSERT_TRUE(NS_SUCCEEDED(res));
for (size_t i=0; i<streams_.size(); ++i) {
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res, peer_->streams_[i], &NrIceMediaStream::ParseAttributes,
candidates_[streams_[i]->name()]), NS_DISPATCH_SYNC);
WrapRunnableRet(&res, peer_->streams_[i], &NrIceMediaStream::ConnectToPeer,
"ufrag", "pass", streams_[i]->GetAttributes()), NS_DISPATCH_SYNC);
ASSERT_TRUE(NS_SUCCEEDED(res));
}
// Start checks on the other peer.
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res, peer_->ice_ctx_->ctx(), &NrIceCtx::StartChecks,
WrapRunnableRet(&res, peer_->ice_ctx_, &NrIceCtx::StartChecks,
offerer_),
NS_DISPATCH_SYNC);
ASSERT_TRUE(NS_SUCCEEDED(res));
@ -831,9 +829,8 @@ class TransportTestPeer : public sigslot::has_slots<> {
TransportLayerDtls *dtls_;
TransportLayerIce *ice_;
RefPtr<DtlsIdentity> identity_;
RefPtr<NrIceCtxHandler> ice_ctx_;
RefPtr<NrIceCtx> ice_ctx_;
std::vector<RefPtr<NrIceMediaStream> > streams_;
std::map<std::string, std::vector<std::string> > candidates_;
TransportTestPeer *peer_;
bool gathering_complete_;
unsigned char fingerprint_[TransportLayerDtls::kMaxDigestLength];

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

@ -74,8 +74,7 @@ extern "C" {
}
#include "nricemediastream.h"
#include "nricectxhandler.h"
#include "nricectx.h"
using namespace mozilla;

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

@ -306,11 +306,7 @@ int nr_ice_candidate_destroy(nr_ice_candidate **candp)
cand=*candp;
if (cand->state == NR_ICE_CAND_STATE_INITIALIZING) {
/* Make sure the ICE ctx isn't still waiting around for this candidate
* to init. */
nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
}
nr_ice_candidate_stop_gathering(cand);
switch(cand->type){
case HOST:
@ -350,12 +346,6 @@ int nr_ice_candidate_destroy(nr_ice_candidate **candp)
break;
}
NR_async_timer_cancel(cand->delay_timer);
NR_async_timer_cancel(cand->ready_cb_timer);
if(cand->resolver_handle){
nr_resolver_cancel(cand->ctx->resolver,cand->resolver_handle);
}
RFREE(cand->foundation);
RFREE(cand->label);
RFREE(cand);
@ -363,6 +353,25 @@ int nr_ice_candidate_destroy(nr_ice_candidate **candp)
return(0);
}
void nr_ice_candidate_stop_gathering(nr_ice_candidate *cand)
{
if (cand->state == NR_ICE_CAND_STATE_INITIALIZING) {
/* Make sure the ICE ctx isn't still waiting around for this candidate
* to init. */
nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
}
NR_async_timer_cancel(cand->delay_timer);
cand->delay_timer=0;
NR_async_timer_cancel(cand->ready_cb_timer);
cand->ready_cb_timer=0;
if(cand->resolver_handle){
nr_resolver_cancel(cand->ctx->resolver,cand->resolver_handle);
cand->resolver_handle=0;
}
}
/* This algorithm is not super-fast, but I don't think we need a hash
table just yet and it produces a small foundation string */
static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand)

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

@ -110,6 +110,7 @@ int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, vo
void nr_ice_candidate_compute_codeword(nr_ice_candidate *cand);
int nr_ice_candidate_process_stun(nr_ice_candidate *cand, UCHAR *msg, int len, nr_transport_addr *faddr);
int nr_ice_candidate_destroy(nr_ice_candidate **candp);
void nr_ice_candidate_stop_gathering(nr_ice_candidate *cand);
int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen);
int nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *attr,nr_ice_media_stream *stream,nr_ice_candidate **candp);
int nr_ice_peer_peer_rflx_candidate_create(nr_ice_ctx *ctx,char *label, nr_ice_component *comp,nr_transport_addr *addr, nr_ice_candidate **candp);

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

@ -497,7 +497,7 @@ int nr_ice_candidate_pair_do_triggered_check(nr_ice_peer_ctx *pctx, nr_ice_cand_
return(_status);
}
int nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair, int move_to_wait_state)
void nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair, int move_to_wait_state)
{
if(pair->state != NR_ICE_PAIR_STATE_FAILED){
/* If it's already running we need to terminate the stun */
@ -510,8 +510,6 @@ int nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair, i
}
nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_CANCELLED);
}
return(0);
}
int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair)
@ -545,10 +543,8 @@ int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair)
return(_status);
}
int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state)
void nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state)
{
int r,_status;
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): setting pair to state %s: %s",
pctx->label,pair->codeword,nr_ice_cand_pair_states[state],pair->as_string);
@ -580,13 +576,8 @@ int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pai
if(pair->state==NR_ICE_PAIR_STATE_FAILED ||
pair->state==NR_ICE_PAIR_STATE_CANCELLED){
if(r=nr_ice_component_failed_pair(pair->remote->component, pair))
ABORT(r);
nr_ice_component_failed_pair(pair->remote->component, pair);
}
_status=0;
abort:
return(_status);
}
int nr_ice_candidate_pair_dump_state(nr_ice_cand_pair *pair, FILE *out)

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

@ -83,9 +83,9 @@ struct nr_ice_cand_pair_ {
int nr_ice_candidate_pair_create(nr_ice_peer_ctx *pctx, nr_ice_candidate *lcand,nr_ice_candidate *rcand,nr_ice_cand_pair **pairp);
int nr_ice_candidate_pair_unfreeze(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair);
int nr_ice_candidate_pair_start(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair);
int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state);
void nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state);
int nr_ice_candidate_pair_dump_state(nr_ice_cand_pair *pair, FILE *out);
int nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair, int move_to_wait_state);
void nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair, int move_to_wait_state);
int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair);
int nr_ice_candidate_pair_do_triggered_check(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair);
int nr_ice_candidate_pair_insert(nr_ice_cand_pair_head *head,nr_ice_cand_pair *pair);

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

@ -657,11 +657,11 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
/* Note: we need to recompute these because
we have not yet computed the values in the peer media stream.*/
lufrag=component->stream->ufrag ? component->stream->ufrag : ctx->ufrag;
lufrag=component->stream->ufrag;
assert(lufrag);
if (!lufrag)
ABORT(R_INTERNAL);
lpwd=component->stream->pwd ? component->stream->pwd :ctx->pwd;
lpwd=component->stream->pwd;
assert(lpwd);
if (!lpwd)
ABORT(R_INTERNAL);
@ -699,6 +699,14 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
return(_status);
}
void nr_ice_component_stop_gathering(nr_ice_component *component)
{
nr_ice_candidate *c1,*c2;
TAILQ_FOREACH_SAFE(c1, &component->candidates, entry_comp, c2){
nr_ice_candidate_stop_gathering(c1);
}
}
static int nr_ice_any_peer_paired(nr_ice_candidate* cand) {
nr_ice_peer_ctx* pctx=STAILQ_FIRST(&cand->ctx->peers);
while(pctx && pctx->state == NR_ICE_PEER_STATE_UNPAIRED){
@ -1254,9 +1262,7 @@ static void nr_ice_component_consent_failed(nr_ice_component *comp)
}
/* We are turning the consent failure into a ICE component failure to
* alert the browser via ICE connection state change about this event. */
if (nr_ice_media_stream_component_failed(comp->stream, comp))
r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): failed to mark component as failed",
comp->ctx->label, comp->stream->label, comp->component_id);
nr_ice_media_stream_component_failed(comp->stream, comp);
}
static void nr_ice_component_consent_timeout_cb(NR_SOCKET s, int how, void *cb_arg)
@ -1515,8 +1521,7 @@ int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pa
p2->state == NR_ICE_PAIR_STATE_CANCELLED);
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s in trigger check queue because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword);
if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2,0))
ABORT(r);
nr_ice_candidate_pair_cancel(pair->pctx,p2,0);
}
p2=TAILQ_NEXT(p2,triggered_check_queue_entry);
@ -1529,8 +1534,7 @@ int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pa
(p2->state == NR_ICE_PAIR_STATE_WAITING))) {
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword);
if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2,0))
ABORT(r);
nr_ice_candidate_pair_cancel(pair->pctx,p2,0);
}
p2=TAILQ_NEXT(p2,check_queue_entry);
@ -1540,8 +1544,7 @@ int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pa
if(r=nr_ice_component_setup_consent(comp))
ABORT(r);
if(r=nr_ice_media_stream_component_nominated(comp->stream,comp))
ABORT(r);
nr_ice_media_stream_component_nominated(comp->stream,comp);
_status=0;
abort:
@ -1577,12 +1580,12 @@ static int nr_ice_component_have_all_pairs_failed(nr_ice_component *comp)
return(1);
}
int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
void nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
{
return nr_ice_component_check_if_failed(comp);
nr_ice_component_check_if_failed(comp);
}
int nr_ice_component_check_if_failed(nr_ice_component *comp)
void nr_ice_component_check_if_failed(nr_ice_component *comp)
{
if (comp->state == NR_ICE_COMPONENT_RUNNING) {
/* Don't do anything to streams that aren't currently running */
@ -1591,11 +1594,9 @@ int nr_ice_component_check_if_failed(nr_ice_component *comp)
if (!comp->stream->pctx->trickle_grace_period_timer &&
nr_ice_component_have_all_pairs_failed(comp)) {
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): All pairs are failed, and grace period has elapsed. Marking component as failed.",comp->stream->pctx->label,comp->stream->label,comp->component_id);
return nr_ice_media_stream_component_failed(comp->stream,comp);
nr_ice_media_stream_component_failed(comp->stream,comp);
}
}
return(0);
}
int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp)

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

@ -86,13 +86,14 @@ typedef STAILQ_HEAD(nr_ice_component_head_,nr_ice_component_) nr_ice_component_h
int nr_ice_component_create(struct nr_ice_media_stream_ *stream, int component_id, nr_ice_component **componentp);
int nr_ice_component_destroy(nr_ice_component **componentp);
int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component);
void nr_ice_component_stop_gathering(nr_ice_component *component);
int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned);
int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote);
int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp, nr_ice_component *pcomp);
int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced);
int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
int nr_ice_component_check_if_failed(nr_ice_component *comp);
void nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
void nr_ice_component_check_if_failed(nr_ice_component *comp);
int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp);
int nr_ice_component_set_failed(nr_ice_component *comp);
int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp);

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

@ -338,28 +338,6 @@ int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out)
#define MAXADDRS 100 /* Ridiculously high */
int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp)
{
int r,_status;
char *ufrag = 0;
char *pwd = 0;
if (r=nr_ice_get_new_ice_ufrag(&ufrag))
ABORT(r);
if (r=nr_ice_get_new_ice_pwd(&pwd))
ABORT(r);
if (r=nr_ice_ctx_create_with_credentials(label, flags, ufrag, pwd, ctxp))
ABORT(r);
_status=0;
abort:
RFREE(ufrag);
RFREE(pwd);
return(_status);
}
int nr_ice_ctx_create_with_credentials(char *label, UINT4 flags, char *ufrag, char *pwd, nr_ice_ctx **ctxp)
{
nr_ice_ctx *ctx=0;
int r,_status;
@ -375,11 +353,6 @@ int nr_ice_ctx_create_with_credentials(char *label, UINT4 flags, char *ufrag, ch
if(!(ctx->label=r_strdup(label)))
ABORT(R_NO_MEMORY);
if(!(ctx->ufrag=r_strdup(ufrag)))
ABORT(r);
if(!(ctx->pwd=r_strdup(pwd)))
ABORT(r);
/* Get the STUN servers */
if(r=NR_reg_get_child_count(NR_ICE_REG_STUN_SRV_PRFX,
(unsigned int *)&ctx->stun_server_ct)||ctx->stun_server_ct==0) {
@ -494,8 +467,6 @@ static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg)
RFREE(f1);
f1=f2;
}
RFREE(ctx->pwd);
RFREE(ctx->ufrag);
STAILQ_FOREACH_SAFE(id1, &ctx->ids, entry, id2){
STAILQ_REMOVE(&ctx->ids,id1,nr_ice_stun_id_,entry);
@ -832,11 +803,11 @@ int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg)
return(_status);
}
int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp)
int nr_ice_add_media_stream(nr_ice_ctx *ctx,const char *label,const char *ufrag,const char *pwd,int components, nr_ice_media_stream **streamp)
{
int r,_status;
if(r=nr_ice_media_stream_create(ctx,label,components,streamp))
if(r=nr_ice_media_stream_create(ctx,label,ufrag,pwd,components,streamp))
ABORT(r);
STAILQ_INSERT_TAIL(&ctx->streams,*streamp,entry);
@ -875,36 +846,9 @@ int nr_ice_remove_media_stream(nr_ice_ctx *ctx,nr_ice_media_stream **streamp)
int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp)
{
char **attrs=0;
int _status;
char *tmp=0;
if(!(attrs=RCALLOC(sizeof(char *)*2)))
ABORT(R_NO_MEMORY);
if(!(tmp=RMALLOC(100)))
ABORT(R_NO_MEMORY);
snprintf(tmp,100,"ice-ufrag:%s",ctx->ufrag);
attrs[0]=tmp;
if(!(tmp=RMALLOC(100)))
ABORT(R_NO_MEMORY);
snprintf(tmp,100,"ice-pwd:%s",ctx->pwd);
attrs[1]=tmp;
*attrctp=2;
*attrsp=attrs;
_status=0;
abort:
if (_status){
if (attrs){
RFREE(attrs[0]);
RFREE(attrs[1]);
}
RFREE(attrs);
}
return(_status);
*attrctp=0;
*attrsp=0;
return(0);
}
static int nr_ice_random_string(char *str, int len)

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

@ -123,9 +123,6 @@ struct nr_ice_ctx_ {
UINT4 flags;
char *label;
char *ufrag;
char *pwd;
UINT4 Ta;
nr_ice_stun_server *stun_servers; /* The list of stun servers */
@ -181,7 +178,7 @@ int nr_ice_set_local_addresses(nr_ice_ctx *ctx, nr_local_addr* stun_addrs, int s
int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg);
int nr_ice_add_candidate(nr_ice_ctx *ctx, nr_ice_candidate *cand);
void nr_ice_gather_finished_cb(NR_SOCKET s, int h, void *cb_arg);
int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp);
int nr_ice_add_media_stream(nr_ice_ctx *ctx,const char *label,const char *ufrag,const char *pwd,int components, nr_ice_media_stream **streamp);
int nr_ice_remove_media_stream(nr_ice_ctx *ctx,nr_ice_media_stream **streamp);
int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp);
int nr_ice_ctx_deliver_packet(nr_ice_ctx *ctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len);

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

@ -44,7 +44,7 @@ static char *nr_ice_media_stream_states[]={"INVALID",
int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state);
int nr_ice_media_stream_create(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp)
int nr_ice_media_stream_create(nr_ice_ctx *ctx,const char *label,const char *ufrag,const char *pwd,int components, nr_ice_media_stream **streamp)
{
int r,_status;
nr_ice_media_stream *stream=0;
@ -57,6 +57,12 @@ int nr_ice_media_stream_create(nr_ice_ctx *ctx,char *label,int components, nr_ic
if(!(stream->label=r_strdup(label)))
ABORT(R_NO_MEMORY);
if(!(stream->ufrag=r_strdup(ufrag)))
ABORT(R_NO_MEMORY);
if(!(stream->pwd=r_strdup(pwd)))
ABORT(R_NO_MEMORY);
stream->ctx=ctx;
STAILQ_INIT(&stream->components);
@ -73,6 +79,9 @@ int nr_ice_media_stream_create(nr_ice_ctx *ctx,char *label,int components, nr_ic
stream->disconnected = 0;
stream->component_ct=components;
stream->ice_state = NR_ICE_MEDIA_STREAM_UNPAIRED;
stream->obsolete = 0;
stream->r2l_user = 0;
stream->l2r_user = 0;
*streamp=stream;
_status=0;
@ -143,12 +152,13 @@ int nr_ice_media_stream_initialize(nr_ice_ctx *ctx, nr_ice_media_stream *stream)
int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attrsp, int *attrctp)
{
int attrct=0;
int attrct=2;
nr_ice_component *comp;
char **attrs=0;
int index=0;
nr_ice_candidate *cand;
int r,_status;
char *tmp=0;
*attrctp=0;
@ -168,11 +178,6 @@ int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attr
comp=STAILQ_NEXT(comp,entry);
}
if(attrct < 1){
r_log(LOG_ICE,LOG_ERR,"ICE-STREAM(%s): Failed to find any components for stream",stream->label);
ABORT(R_FAILED);
}
/* Make the array we'll need */
if(!(attrs=RCALLOC(sizeof(char *)*attrct)))
ABORT(R_NO_MEMORY);
@ -208,6 +213,17 @@ int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attr
comp=STAILQ_NEXT(comp,entry);
}
/* Now, ufrag and pwd */
if(!(tmp=RMALLOC(100)))
ABORT(R_NO_MEMORY);
snprintf(tmp,100,"ice-ufrag:%s",stream->ufrag);
attrs[index++]=tmp;
if(!(tmp=RMALLOC(100)))
ABORT(R_NO_MEMORY);
snprintf(tmp,100,"ice-pwd:%s",stream->pwd);
attrs[index++]=tmp;
*attrsp=attrs;
*attrctp=attrct;
@ -392,6 +408,11 @@ int nr_ice_media_stream_start_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream
ABORT(R_INTERNAL);
}
if (stream->local_stream->obsolete) {
assert(0);
ABORT(R_INTERNAL);
}
/* Even if the stream is completed already remote can still create a new
* triggered check request which needs to fire, but not change our stream
* state. */
@ -587,6 +608,42 @@ int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state)
return(0);
}
void nr_ice_media_stream_stop_checking(nr_ice_media_stream *str)
{
nr_ice_cand_pair *p;
nr_ice_component *comp;
/* Cancel candidate pairs */
p=TAILQ_FIRST(&str->check_list);
while(p){
nr_ice_candidate_pair_cancel(p->pctx,p,0);
p=TAILQ_NEXT(p,check_queue_entry);
}
if(str->timer) {
NR_async_timer_cancel(str->timer);
str->timer = 0;
}
/* Cancel consent timers in case it is running already */
comp=STAILQ_FIRST(&str->components);
while(comp){
nr_ice_component_consent_destroy(comp);
comp=STAILQ_NEXT(comp,entry);
}
}
void nr_ice_media_stream_set_obsolete(nr_ice_media_stream *str)
{
nr_ice_component *c1,*c2;
str->obsolete = 1;
STAILQ_FOREACH_SAFE(c1, &str->components, entry, c2){
nr_ice_component_stop_gathering(c1);
}
nr_ice_media_stream_stop_checking(str);
}
void nr_ice_media_stream_refresh_consent_all(nr_ice_media_stream *stream)
{
@ -626,7 +683,9 @@ void nr_ice_media_stream_set_disconnected(nr_ice_media_stream *stream, int disco
stream->disconnected = disconnected;
if (disconnected == NR_ICE_MEDIA_STREAM_DISCONNECTED) {
nr_ice_peer_ctx_disconnected(stream->pctx);
if (!stream->local_stream->obsolete) {
nr_ice_peer_ctx_disconnected(stream->pctx);
}
} else {
nr_ice_peer_ctx_check_if_connected(stream->pctx);
}
@ -658,9 +717,8 @@ int nr_ice_media_stream_check_if_connected(nr_ice_media_stream *stream)
/* S OK, this component has a nominated. If every component has a nominated,
the stream is ready */
int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component)
void nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component)
{
int r,_status;
nr_ice_component *comp;
comp=STAILQ_FIRST(&stream->components);
@ -675,7 +733,7 @@ int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_c
/* At least one un-nominated component */
if(comp)
goto done;
return;
/* All done... */
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/ICE-STREAM(%s): all active components have nominated candidate pairs",stream->pctx->label,stream->label);
@ -687,25 +745,16 @@ int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_c
stream->timer=0;
}
if (stream->pctx->handler) {
if (stream->pctx->handler && !stream->local_stream->obsolete) {
stream->pctx->handler->vtbl->stream_ready(stream->pctx->handler->obj,stream->local_stream);
}
/* Now tell the peer_ctx that we're connected */
if(r=nr_ice_peer_ctx_check_if_connected(stream->pctx))
ABORT(r);
done:
_status=0;
abort:
return(_status);
nr_ice_peer_ctx_check_if_connected(stream->pctx);
}
int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component)
void nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component)
{
int r,_status;
nr_ice_cand_pair *p2;
component->state=NR_ICE_COMPONENT_FAILED;
/* at least one component failed in this media stream, so the entire
@ -713,35 +762,14 @@ int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_comp
nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_FAILED);
/* OK, we need to cancel off everything on this component */
p2=TAILQ_FIRST(&stream->check_list);
while(p2){
if(r=nr_ice_candidate_pair_cancel(p2->pctx,p2,0))
ABORT(r);
nr_ice_media_stream_stop_checking(stream);
p2=TAILQ_NEXT(p2,check_queue_entry);
}
/* Cancel our timer */
if(stream->timer){
NR_async_timer_cancel(stream->timer);
stream->timer=0;
}
/* Cancel consent timers in case it is running already */
nr_ice_component_consent_destroy(component);
if (stream->pctx->handler) {
if (stream->pctx->handler && !stream->local_stream->obsolete) {
stream->pctx->handler->vtbl->stream_failed(stream->pctx->handler->obj,stream->local_stream);
}
/* Now tell the peer_ctx that we're connected */
if(r=nr_ice_peer_ctx_check_if_connected(stream->pctx))
ABORT(r);
_status=0;
abort:
return(_status);
/* Now tell the peer_ctx that we've failed */
nr_ice_peer_ctx_check_if_connected(stream->pctx);
}
int nr_ice_media_stream_get_best_candidate(nr_ice_media_stream *str, int component, nr_ice_candidate **candp)

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

@ -55,6 +55,10 @@ struct nr_ice_media_stream_ {
Data r2l_pass; /* The password for incoming requests */
Data l2r_pass; /* The password for outcoming requests */
int ice_state;
/* The stream is being replaced by another, so it will not continue any ICE
* processing. If this stream is connected already, traffic can continue to
* flow for a limited time while the new stream gets ready. */
int obsolete;
#define NR_ICE_MEDIA_STREAM_UNPAIRED 1
#define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN 2
@ -78,7 +82,7 @@ struct nr_ice_media_stream_ {
typedef STAILQ_HEAD(nr_ice_media_stream_head_,nr_ice_media_stream_) nr_ice_media_stream_head;
int nr_ice_media_stream_create(struct nr_ice_ctx_ *ctx,char *label, int components, nr_ice_media_stream **streamp);
int nr_ice_media_stream_create(struct nr_ice_ctx_ *ctx,const char *label,const char *ufrag,const char *pwd,int components, nr_ice_media_stream **streamp);
int nr_ice_media_stream_destroy(nr_ice_media_stream **streamp);
int nr_ice_media_stream_finalize(nr_ice_media_stream *lstr,nr_ice_media_stream *rstr);
int nr_ice_media_stream_initialize(struct nr_ice_ctx_ *ctx, nr_ice_media_stream *stream);
@ -90,13 +94,15 @@ int nr_ice_media_stream_service_pre_answer_requests(nr_ice_peer_ctx *pctx,nr_ice
int nr_ice_media_stream_unfreeze_pairs(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
int nr_ice_media_stream_unfreeze_pairs_foundation(nr_ice_media_stream *stream, char *foundation);
int nr_ice_media_stream_dump_state(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream,FILE *out);
int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component);
int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component);
void nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component);
void nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component);
void nr_ice_media_stream_refresh_consent_all(nr_ice_media_stream *stream);
void nr_ice_media_stream_disconnect_all_components(nr_ice_media_stream *stream);
void nr_ice_media_stream_set_disconnected(nr_ice_media_stream *stream, int disconnected);
int nr_ice_media_stream_check_if_connected(nr_ice_media_stream *stream);
int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state);
void nr_ice_media_stream_stop_checking(nr_ice_media_stream *str);
void nr_ice_media_stream_set_obsolete(nr_ice_media_stream *str);
int nr_ice_media_stream_get_best_candidate(nr_ice_media_stream *str, int component, nr_ice_candidate **candp);
int nr_ice_media_stream_send(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, UCHAR *data, int len);
int nr_ice_media_stream_get_active(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, nr_ice_candidate **local, nr_ice_candidate **remote);

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

@ -380,6 +380,7 @@ nr_ice_peer_ctx_parse_media_stream_attribute(nr_ice_peer_ctx *pctx, nr_ice_media
if (*str == '\0')
ABORT(R_BAD_DATA);
RFREE(stream->ufrag);
if ((r=grab_token(&str, &stream->ufrag)))
ABORT(r);
}
@ -392,6 +393,7 @@ nr_ice_peer_ctx_parse_media_stream_attribute(nr_ice_peer_ctx *pctx, nr_ice_media
if (*str == '\0')
ABORT(R_BAD_DATA);
RFREE(stream->pwd);
if ((r=grab_token(&str, &stream->pwd)))
ABORT(r);
}
@ -490,6 +492,7 @@ nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs, int
}
else if (!strncasecmp(str, "ice-lite", 8)) {
pctx->peer_lite = 1;
pctx->controlling = 0;
fast_forward(&str, 8);
}
@ -506,11 +509,6 @@ nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs, int
skip_whitespace(&str);
if (*str == '\0')
ABORT(R_BAD_DATA);
RFREE(pctx->peer_ufrag);
pctx->peer_ufrag = 0;
if ((r=grab_token(&str, &pctx->peer_ufrag)))
ABORT(r);
}
else if (!strncasecmp(str, "ice-pwd:", 8)) {
fast_forward(&str, 8);
@ -520,11 +518,6 @@ nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs, int
skip_whitespace(&str);
if (*str == '\0')
ABORT(R_BAD_DATA);
RFREE(pctx->peer_pwd);
pctx->peer_pwd = 0;
if ((r=grab_token(&str, &pctx->peer_pwd)))
ABORT(r);
}
else if (!strncasecmp(str, "ice-options:", 12)) {
fast_forward(&str, 12);

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

@ -99,7 +99,7 @@ int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_
/*
Note: use component_ct from our own stream since components other
than this offered by the other side are unusable */
if(r=nr_ice_media_stream_create(pctx->ctx,stream->label,stream->component_ct,&pstream))
if(r=nr_ice_media_stream_create(pctx->ctx,stream->label,"","",stream->component_ct,&pstream))
ABORT(r);
/* Match up the local and remote components */
@ -120,12 +120,12 @@ int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_
/* Now that we have the ufrag and password, compute all the username/password
pairs */
lufrag=stream->ufrag?stream->ufrag:pctx->ctx->ufrag;
lpwd=stream->pwd?stream->pwd:pctx->ctx->pwd;
lufrag=stream->ufrag;
lpwd=stream->pwd;
assert(lufrag);
assert(lpwd);
rufrag=pstream->ufrag?pstream->ufrag:pctx->peer_ufrag;
rpwd=pstream->pwd?pstream->pwd:pctx->peer_pwd;
rufrag=pstream->ufrag;
rpwd=pstream->pwd;
if (!rufrag || !rpwd)
ABORT(R_BAD_DATA);
@ -470,8 +470,6 @@ static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg)
NR_async_timer_cancel(pctx->connected_cb_timer);
RFREE(pctx->label);
RFREE(pctx->peer_ufrag);
RFREE(pctx->peer_pwd);
STAILQ_FOREACH_SAFE(str1, &pctx->peer_streams, entry, str2){
STAILQ_REMOVE(&pctx->peer_streams,str1,nr_ice_media_stream_,entry);
@ -534,10 +532,7 @@ int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first)
pctx->connected_cb_timer = 0;
pctx->checks_started = 0;
if((r=nr_ice_peer_ctx_check_if_connected(pctx))) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) initial connected check failed",pctx->ctx->label,pctx->label);
ABORT(r);
}
nr_ice_peer_ctx_check_if_connected(pctx);
if (pctx->reported_connected) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) in %s all streams were done",pctx->ctx->label,pctx->label,__FUNCTION__);
@ -717,29 +712,30 @@ static void nr_ice_peer_ctx_fire_connected(NR_SOCKET s, int how, void *cb_arg)
/* Examine all the streams to see if we're
maybe miraculously connected */
int nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx)
void nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx)
{
int _status;
nr_ice_media_stream *str;
int failed=0;
int succeeded=0;
str=STAILQ_FIRST(&pctx->peer_streams);
while(str){
if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED){
succeeded++;
}
else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED){
failed++;
}
else{
break;
if (!str->local_stream->obsolete){
if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED){
succeeded++;
}
else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED){
failed++;
}
else{
break;
}
}
str=STAILQ_NEXT(str,entry);
}
if(str)
goto done; /* Something isn't done */
return; /* Something isn't done */
/* OK, we're finished, one way or another */
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): all checks completed success=%d fail=%d",pctx->label,succeeded,failed);
@ -752,10 +748,6 @@ int nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx)
assert(!pctx->connected_cb_timer);
NR_ASYNC_TIMER_SET(0,nr_ice_peer_ctx_fire_connected,pctx,&pctx->connected_cb_timer);
}
done:
_status=0;
return(_status);
}

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

@ -52,8 +52,6 @@ struct nr_ice_peer_ctx_ {
UCHAR controlling_conflict_resolved;
UINT8 tiebreaker;
char *peer_ufrag;
char *peer_pwd;
int peer_lite;
int peer_ice_mismatch;
@ -89,7 +87,7 @@ void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx);
void nr_ice_peer_ctx_connected(nr_ice_peer_ctx *pctx);
int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out);
int nr_ice_peer_ctx_log_state(nr_ice_peer_ctx *pctx);
int nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx);
void nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx);
int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp);
int nr_ice_peer_ctx_deliver_packet_maybe(nr_ice_peer_ctx *pctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len);
int nr_ice_peer_ctx_disable_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *lstream, int component_id);

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

@ -85,8 +85,7 @@ namespace mozilla {
MOZ_MTLOG_MODULE("mtransport")
TransportLayerIce::TransportLayerIce()
: stream_(nullptr), component_(0),
old_stream_(nullptr)
: stream_(nullptr), component_(0)
{
// setup happens later
}
@ -108,17 +107,6 @@ void TransportLayerIce::SetParameters(RefPtr<NrIceMediaStream> stream,
return;
}
// If SetParameters is called and we already have a stream_, this means
// we're handling an ICE restart. We need to hold the old stream until
// we know the new stream is working.
if (stream_ && !old_stream_ && (stream_ != stream)) {
// Here we leave the old stream's signals connected until we don't need
// it anymore. They will be disconnected if ice restart is successful.
old_stream_ = stream_;
MOZ_MTLOG(ML_INFO, LAYER_INFO << "SetParameters save old stream("
<< old_stream_->name() << ")");
}
stream_ = stream;
component_ = component;
@ -135,48 +123,11 @@ void TransportLayerIce::PostSetup() {
}
}
void TransportLayerIce::ResetOldStream() {
if (old_stream_ == nullptr) {
return; // no work to do
}
// ICE restart successful on the new stream, we can forget the old stream now
MOZ_MTLOG(ML_INFO, LAYER_INFO << "ResetOldStream(" << old_stream_->name()
<< ")");
old_stream_->SignalReady.disconnect(this);
old_stream_->SignalFailed.disconnect(this);
old_stream_->SignalPacketReceived.disconnect(this);
old_stream_ = nullptr;
}
void TransportLayerIce::RestoreOldStream() {
if (old_stream_ == nullptr) {
return; // no work to do
}
// ICE restart rollback, we need to restore the old stream
MOZ_MTLOG(ML_INFO, LAYER_INFO << "RestoreOldStream(" << old_stream_->name()
<< ")");
stream_->SignalReady.disconnect(this);
stream_->SignalFailed.disconnect(this);
stream_->SignalPacketReceived.disconnect(this);
stream_ = old_stream_;
old_stream_ = nullptr;
if (stream_->state() == NrIceMediaStream::ICE_OPEN) {
IceReady(stream_);
} else if (stream_->state() == NrIceMediaStream::ICE_CLOSED) {
IceFailed(stream_);
}
// No events are fired when the stream is ICE_CONNECTING. If the
// restored stream is ICE_CONNECTING, IceReady/IceFailed will fire
// later.
}
TransportResult TransportLayerIce::SendPacket(MediaPacket& packet) {
CheckThread();
// use old_stream_ until stream_ is ready
nsresult res = (old_stream_?old_stream_:stream_)->SendPacket(component_,
packet.data(),
packet.len());
nsresult res = stream_->SendPacket(component_,
packet.data(),
packet.len());
if (!NS_SUCCEEDED(res)) {
return (res == NS_BASE_STREAM_WOULD_BLOCK) ?

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

@ -58,9 +58,6 @@ class TransportLayerIce : public TransportLayer {
RefPtr<NrIceMediaStream> stream_;
int component_;
// used to hold the old stream
RefPtr<NrIceMediaStream> old_stream_;
};
} // close namespace

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

@ -81,32 +81,9 @@ public:
}
protected:
struct TransportData {
std::string mIceUfrag;
std::string mIcePwd;
int iceCredentialSerial;
std::map<std::string, std::vector<uint8_t> > mFingerprints;
};
void
GenerateNewIceCredentials(const JsepSessionImpl& session,
TransportData& tdata)
{
std::ostringstream ostr;
ostr << session.GetName() << "-" << ++tdata.iceCredentialSerial;
// Values here semi-borrowed from JSEP draft.
tdata.mIceUfrag = ostr.str() + "-ufrag";
tdata.mIcePwd = ostr.str() + "-1234567890";
}
void
ModifyOffererIceCredentials()
{
GenerateNewIceCredentials(*mSessionOff, *mOffererTransport);
mSessionOff->SetIceCredentials(mOffererTransport->mIceUfrag,
mOffererTransport->mIcePwd);
}
void
AddDtlsFingerprint(const std::string& alg, JsepSessionImpl& session,
TransportData& tdata)
@ -121,9 +98,6 @@ protected:
void
AddTransportData(JsepSessionImpl& session, TransportData& tdata)
{
tdata.iceCredentialSerial = 0;
GenerateNewIceCredentials(session, tdata);
session.SetIceCredentials(tdata.mIceUfrag, tdata.mIcePwd);
AddDtlsFingerprint("sha-1", session, tdata);
AddDtlsFingerprint("sha-256", session, tdata);
}
@ -816,13 +790,6 @@ protected:
JsepAnswerOptions options;
std::string answer;
// detect ice restart and generate new ice credentials (like
// PeerConnectionImpl does).
if (mSessionAns->RemoteIceIsRestarting()) {
GenerateNewIceCredentials(*mSessionAns, *mAnswererTransport);
mSessionAns->SetIceCredentials(mAnswererTransport->mIceUfrag,
mAnswererTransport->mIcePwd);
}
nsresult rv = mSessionAns->CreateAnswer(options, &answer);
EXPECT_EQ(NS_OK, rv);
@ -1342,9 +1309,10 @@ protected:
const char* replaceStr) const
{
if (searchStr[0] == '\0') return;
size_t pos;
while ((pos = sdp->find(searchStr)) != std::string::npos) {
size_t pos = 0;
while ((pos = sdp->find(searchStr, pos)) != std::string::npos) {
sdp->replace(pos, strlen(searchStr), replaceStr);
pos += strlen(replaceStr);
}
}
@ -1533,8 +1501,8 @@ private:
if (!mSdpHelper.IsBundleSlave(*sdp, i)) {
const SdpAttributeList& attrs = msection.GetAttributeList();
ASSERT_EQ(source.mIceUfrag, attrs.GetIceUfrag());
ASSERT_EQ(source.mIcePwd, attrs.GetIcePwd());
ASSERT_FALSE(attrs.GetIceUfrag().empty());
ASSERT_FALSE(attrs.GetIcePwd().empty());
const SdpFingerprintAttributeList& fps = attrs.GetFingerprint();
for (auto fp = fps.mFingerprints.begin(); fp != fps.mFingerprints.end();
++fp) {
@ -4286,7 +4254,6 @@ TEST_F(JsepSessionTest, TestIceRestart)
JsepOfferOptions options;
options.mIceRestart = Some(true);
ModifyOffererIceCredentials();
std::string reoffer = CreateOffer(Some(options));
SetLocalOffer(reoffer, CHECK_SUCCESS);
@ -4333,6 +4300,26 @@ TEST_F(JsepSessionTest, TestIceRestart)
reanswerMediaAttrs.GetIcePwd().c_str());
ASSERT_NE(answerMediaAttrs.GetIceUfrag().c_str(),
reanswerMediaAttrs.GetIceUfrag().c_str());
auto offererTransceivers = mSessionOff->GetTransceivers();
auto answererTransceivers = mSessionAns->GetTransceivers();
ASSERT_EQ(reofferMediaAttrs.GetIceUfrag(),
offererTransceivers[0]->mTransport.mLocalUfrag);
ASSERT_EQ(reofferMediaAttrs.GetIceUfrag(),
answererTransceivers[0]->mTransport.mIce->GetUfrag());
ASSERT_EQ(reofferMediaAttrs.GetIcePwd(),
offererTransceivers[0]->mTransport.mLocalPwd);
ASSERT_EQ(reofferMediaAttrs.GetIcePwd(),
answererTransceivers[0]->mTransport.mIce->GetPassword());
ASSERT_EQ(reanswerMediaAttrs.GetIceUfrag(),
answererTransceivers[0]->mTransport.mLocalUfrag);
ASSERT_EQ(reanswerMediaAttrs.GetIceUfrag(),
offererTransceivers[0]->mTransport.mIce->GetUfrag());
ASSERT_EQ(reanswerMediaAttrs.GetIcePwd(),
answererTransceivers[0]->mTransport.mLocalPwd);
ASSERT_EQ(reanswerMediaAttrs.GetIcePwd(),
offererTransceivers[0]->mTransport.mIce->GetPassword());
}
TEST_F(JsepSessionTest, TestAnswererIndicatingIceRestart)
@ -4354,7 +4341,8 @@ TEST_F(JsepSessionTest, TestAnswererIndicatingIceRestart)
std::string reanswer = CreateAnswer();
// change the ice pwd and ufrag
ReplaceInSdp(&reanswer, "Answerer-1-", "bad-2-");
ReplaceInSdp(&reanswer, "a=ice-ufrag:", "a=ice-ufrag:bad-");
ReplaceInSdp(&reanswer, "a=ice-pwd:", "a=ice-pwd:bad-");
SetLocalAnswer(reanswer, CHECK_SUCCESS);
nsresult rv = mSessionOff->SetRemoteDescription(kJsepSdpAnswer, reanswer);
ASSERT_NE(NS_OK, rv); // NS_ERROR_INVALID_ARG

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

@ -99,13 +99,8 @@ public:
}
// Set up the ICE And DTLS data.
virtual nsresult SetIceCredentials(const std::string& ufrag,
const std::string& pwd) = 0;
virtual const std::string& GetUfrag() const = 0;
virtual const std::string& GetPwd() const = 0;
virtual nsresult SetBundlePolicy(JsepBundlePolicy policy) = 0;
virtual bool RemoteIsIceLite() const = 0;
virtual bool RemoteIceIsRestarting() const = 0;
virtual std::vector<std::string> GetIceOptions() const = 0;
virtual nsresult AddDtlsFingerprint(const std::string& algorithm,
@ -185,6 +180,7 @@ public:
// ICE controlling or controlled
virtual bool IsIceControlling() const = 0;
virtual bool IsOfferer() const = 0;
virtual bool IsIceRestarting() const = 0;
virtual const std::string
GetLastError() const

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

@ -55,6 +55,21 @@ static std::bitset<128> GetForbiddenSdpPayloadTypes() {
return forbidden;
}
static std::string GetRandomHex()
{
uint32_t rand;
SECStatus rv =
PK11_GenerateRandom(reinterpret_cast<unsigned char*>(&rand), sizeof(rand));
if (rv != SECSuccess) {
MOZ_CRASH();
return "";
}
std::ostringstream os;
os << std::hex << std::setfill('0') << std::setw(8) << rand;
return os.str();
}
nsresult
JsepSessionImpl::Init()
{
@ -73,6 +88,8 @@ JsepSessionImpl::Init()
mRunSdpComparer = Preferences::GetBool("media.peerconnection.sdp.rust.compare",
false);
mIceUfrag = GetRandomHex();
mIcePwd = GetRandomHex();
return NS_OK;
}
@ -112,17 +129,6 @@ JsepSessionImpl::AddTransceiver(RefPtr<JsepTransceiver> transceiver)
return NS_OK;
}
nsresult
JsepSessionImpl::SetIceCredentials(const std::string& ufrag,
const std::string& pwd)
{
mLastError.clear();
mIceUfrag = ufrag;
mIcePwd = pwd;
return NS_OK;
}
nsresult
JsepSessionImpl::SetBundlePolicy(JsepBundlePolicy policy)
{
@ -420,13 +426,15 @@ JsepSessionImpl::CreateOffer(const JsepOfferOptions& options,
std::string* offer)
{
mLastError.clear();
mLocalIceIsRestarting = options.mIceRestart.isSome() && *(options.mIceRestart);
if (mState != kJsepStateStable) {
JSEP_SET_ERROR("Cannot create offer in state " << GetStateStr(mState));
return NS_ERROR_UNEXPECTED;
}
// This is one of those places where CreateOffer sets some state.
SetIceRestarting(options.mIceRestart.isSome() && *(options.mIceRestart));
UniquePtr<Sdp> sdp;
// Make the basic SDP that is common to offer/answer.
@ -976,7 +984,7 @@ JsepSessionImpl::SetRemoteDescription(JsepSdpType type, const std::string& sdp)
if (NS_SUCCEEDED(rv)) {
mRemoteIsIceLite = iceLite;
mIceOptions = iceOptions;
mRemoteIceIsRestarting = iceRestarting;
SetIceRestarting(iceRestarting);
}
return rv;
@ -986,6 +994,10 @@ nsresult
JsepSessionImpl::HandleNegotiatedSession(const UniquePtr<Sdp>& local,
const UniquePtr<Sdp>& remote)
{
// local ufrag/pwd has been negotiated; we will never go back to the old ones
mOldIceUfrag.clear();
mOldIcePwd.clear();
bool remoteIceLite =
remote->GetAttributeList().HasAttribute(SdpAttribute::kIceLiteAttribute);
@ -1136,13 +1148,14 @@ JsepSessionImpl::EnsureHasOwnTransport(const SdpMediaSection& msection,
{
JsepTransport& transport = transceiver->mTransport;
// TODO: Detect ICE restart on a per-msection basis.
if (mLocalIceIsRestarting || mRemoteIceIsRestarting ||
!transceiver->HasOwnTransport()) {
if (!transceiver->HasOwnTransport()) {
// Transceiver didn't own this transport last time, it won't now either
transport.Close();
}
transport.mLocalUfrag = msection.GetAttributeList().GetIceUfrag();
transport.mLocalPwd = msection.GetAttributeList().GetIcePwd();
transceiver->ClearBundleLevel();
if (mSdpHelper.HasRtcp(msection.GetProtocol())) {
@ -1169,7 +1182,9 @@ JsepSessionImpl::FinalizeTransport(const SdpAttributeList& remote,
return NS_OK;
}
if (!transport->mIce) {
if (!transport->mIce ||
transport->mIce->mUfrag != remote.GetIceUfrag() ||
transport->mIce->mPwd != remote.GetIcePwd()) {
UniquePtr<JsepIceTransport> ice = MakeUnique<JsepIceTransport>();
// We do sanity-checking for these in ParseSdp
@ -1254,8 +1269,7 @@ JsepSessionImpl::CopyPreviousTransportParams(const Sdp& oldAnswer,
mSdpHelper.AreOldTransportParamsValid(oldAnswer,
offerersPreviousSdp,
newOffer,
i) &&
!mRemoteIceIsRestarting
i)
) {
// If newLocal is an offer, this will be the number of components we used
// last time, and if it is an answer, this will be the number of
@ -1798,8 +1812,7 @@ JsepSessionImpl::ValidateRemoteDescription(const Sdp& description)
bool differ = mSdpHelper.IceCredentialsDiffer(newMsection, oldMsection);
// Detect bad answer ICE restart when offer doesn't request ICE restart
if (mIsOfferer && differ && !mLocalIceIsRestarting) {
if (mIsOfferer && differ && !IsIceRestarting()) {
JSEP_SET_ERROR("Remote description indicates ICE restart but offer did not "
"request ICE restart (new remote description changes either "
"the ice-ufrag or ice-pwd)");
@ -2366,6 +2379,28 @@ JsepSessionImpl::GetAnswer() const
: mCurrentLocalDescription.get();
}
void
JsepSessionImpl::SetIceRestarting(bool restarting)
{
if (restarting) {
// not restarting -> restarting
if (!IsIceRestarting()) {
// We don't set this more than once, so the old ufrag/pwd is preserved
// even if we CreateOffer({iceRestart:true}) multiple times in a row.
mOldIceUfrag = mIceUfrag;
mOldIcePwd = mIcePwd;
}
mIceUfrag = GetRandomHex();
mIcePwd = GetRandomHex();
} else if (IsIceRestarting()) {
// restarting -> not restarting, restore old ufrag/pwd
mIceUfrag = mOldIceUfrag;
mIcePwd = mOldIcePwd;
mOldIceUfrag.clear();
mOldIcePwd.clear();
}
}
nsresult
JsepSessionImpl::Close()
{

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

@ -36,9 +36,7 @@ public:
mIsOfferer(false),
mWasOffererLastTime(false),
mIceControlling(false),
mLocalIceIsRestarting(false),
mRemoteIsIceLite(false),
mRemoteIceIsRestarting(false),
mBundlePolicy(kBundleBalanced),
mSessionId(0),
mSessionVersion(0),
@ -54,10 +52,6 @@ public:
// Implement JsepSession methods.
virtual nsresult Init() override;
virtual nsresult SetIceCredentials(const std::string& ufrag,
const std::string& pwd) override;
virtual const std::string& GetUfrag() const override { return mIceUfrag; }
virtual const std::string& GetPwd() const override { return mIcePwd; }
nsresult SetBundlePolicy(JsepBundlePolicy policy) override;
virtual bool
@ -66,12 +60,6 @@ public:
return mRemoteIsIceLite;
}
virtual bool
RemoteIceIsRestarting() const override
{
return mRemoteIceIsRestarting;
}
virtual std::vector<std::string>
GetIceOptions() const override
{
@ -160,6 +148,12 @@ public:
return mIsOfferer;
}
virtual bool
IsIceRestarting() const override
{
return !mOldIceUfrag.empty();
}
virtual const std::vector<RefPtr<JsepTransceiver>>&
GetTransceivers() const override {
return mTransceivers;
@ -262,6 +256,7 @@ private:
mozilla::Sdp* GetParsedRemoteDescription(JsepDescriptionPendingOrCurrent type)
const;
const Sdp* GetAnswer() const;
void SetIceRestarting(bool restarting);
// !!!NOT INDEXED BY LEVEL!!! These are in the order they were created in. The
// level mapping is done with JsepTransceiver::mLevel.
@ -274,9 +269,9 @@ private:
bool mIceControlling;
std::string mIceUfrag;
std::string mIcePwd;
bool mLocalIceIsRestarting;
std::string mOldIceUfrag;
std::string mOldIcePwd;
bool mRemoteIsIceLite;
bool mRemoteIceIsRestarting;
std::vector<std::string> mIceOptions;
JsepBundlePolicy mBundlePolicy;
std::vector<JsepDtlsFingerprint> mDtlsFingerprints;

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

@ -101,6 +101,8 @@ public:
mDtls.reset(orig.mDtls ? new JsepDtlsTransport(*orig.mDtls) : nullptr);
mTransportId = orig.mTransportId;
mComponents = orig.mComponents;
mLocalUfrag = orig.mLocalUfrag;
mLocalPwd = orig.mLocalPwd;
}
return *this;
}
@ -111,6 +113,8 @@ public:
mTransportId.clear();
mIce.reset();
mDtls.reset();
mLocalUfrag.clear();
mLocalPwd.clear();
}
// Unique identifier for this transport within this call. Group?
@ -122,6 +126,8 @@ public:
// Number of required components.
size_t mComponents;
std::string mLocalUfrag;
std::string mLocalPwd;
};
} // namespace mozilla

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

@ -692,15 +692,6 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
return res;
}
res = mJsepSession->SetIceCredentials(mMedia->ice_ctx()->ufrag(),
mMedia->ice_ctx()->pwd());
if (NS_FAILED(res)) {
CSFLogError(LOGTAG, "%s: Couldn't set ICE credentials, res=%u",
__FUNCTION__,
static_cast<unsigned>(res));
return res;
}
res = mJsepSession->SetBundlePolicy(aConfiguration.getBundlePolicy());
if (NS_FAILED(res)) {
CSFLogError(LOGTAG, "%s: Couldn't set bundle policy, res=%u, error=%s",
@ -1481,13 +1472,6 @@ NS_IMETHODIMP
PeerConnectionImpl::CreateOffer(const JsepOfferOptions& aOptions)
{
PC_AUTO_ENTER_API_CALL(true);
bool restartIce = aOptions.mIceRestart.isSome() && *(aOptions.mIceRestart);
if (!restartIce &&
mMedia->GetIceRestartState() ==
PeerConnectionMedia::ICE_RESTART_PROVISIONAL) {
RollbackIceRestart();
}
RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return NS_OK;
@ -1503,36 +1487,7 @@ PeerConnectionImpl::CreateOffer(const JsepOfferOptions& aOptions)
CSFLogDebug(LOGTAG, "CreateOffer()");
bool iceRestartPrimed = false;
nsresult nrv;
if (restartIce &&
!mJsepSession->GetLocalDescription(kJsepDescriptionCurrent).empty()) {
// If restart is requested and a restart is already in progress, we
// need to make room for the restart request so we either rollback
// or finalize to "clear" the previous restart.
if (mMedia->GetIceRestartState() ==
PeerConnectionMedia::ICE_RESTART_PROVISIONAL) {
// we're mid-restart and can rollback
RollbackIceRestart();
} else if (mMedia->GetIceRestartState() ==
PeerConnectionMedia::ICE_RESTART_COMMITTED) {
// we're mid-restart and can't rollback, finalize restart even
// though we're not really ready yet
FinalizeIceRestart();
}
CSFLogInfo(LOGTAG, "Offerer restarting ice");
nrv = SetupIceRestartCredentials();
if (NS_FAILED(nrv)) {
CSFLogError(LOGTAG, "%s: SetupIceRestart failed, res=%u",
__FUNCTION__,
static_cast<unsigned>(nrv));
return nrv;
}
iceRestartPrimed = true;
}
nrv = ConfigureJsepSessionCodecs();
nsresult nrv = ConfigureJsepSessionCodecs();
if (NS_FAILED(nrv)) {
CSFLogError(LOGTAG, "Failed to configure codecs");
return nrv;
@ -1558,19 +1513,8 @@ PeerConnectionImpl::CreateOffer(const JsepOfferOptions& aOptions)
CSFLogError(LOGTAG, "%s: pc = %s, error = %s",
__FUNCTION__, mHandle.c_str(), errorString.c_str());
if (iceRestartPrimed) {
// reset the ice credentials because CreateOffer failed
ResetIceCredentials();
}
pco->OnCreateOfferError(error, ObString(errorString.c_str()), rv);
} else {
// wait until we know CreateOffer succeeds before we actually start
// the ice restart gears turning.
if (iceRestartPrimed) {
BeginIceRestart();
}
UpdateSignalingState();
pco->OnCreateOfferSuccess(ObString(offer.c_str()), rv);
}
@ -1590,32 +1534,13 @@ PeerConnectionImpl::CreateAnswer()
CSFLogDebug(LOGTAG, "CreateAnswer()");
bool iceRestartPrimed = false;
nsresult nrv;
if (mJsepSession->RemoteIceIsRestarting()) {
if (mMedia->GetIceRestartState() ==
PeerConnectionMedia::ICE_RESTART_COMMITTED) {
FinalizeIceRestart();
} else if (!mMedia->IsIceRestarting()) {
CSFLogInfo(LOGTAG, "Answerer restarting ice");
nrv = SetupIceRestartCredentials();
if (NS_FAILED(nrv)) {
CSFLogError(LOGTAG, "%s: SetupIceRestart failed, res=%u",
__FUNCTION__,
static_cast<unsigned>(nrv));
return nrv;
}
iceRestartPrimed = true;
}
}
STAMP_TIMECARD(mTimeCard, "Create Answer");
// TODO(bug 1098015): Once RTCAnswerOptions is standardized, we'll need to
// add it as a param to CreateAnswer, and convert it here.
JsepAnswerOptions options;
std::string answer;
nrv = mJsepSession->CreateAnswer(options, &answer);
nsresult nrv = mJsepSession->CreateAnswer(options, &answer);
JSErrorResult rv;
if (NS_FAILED(nrv)) {
Error error;
@ -1631,19 +1556,8 @@ PeerConnectionImpl::CreateAnswer()
CSFLogError(LOGTAG, "%s: pc = %s, error = %s",
__FUNCTION__, mHandle.c_str(), errorString.c_str());
if (iceRestartPrimed) {
// reset the ice credentials because CreateAnswer failed
ResetIceCredentials();
}
pco->OnCreateAnswerError(error, ObString(errorString.c_str()), rv);
} else {
// wait until we know CreateAnswer succeeds before we actually start
// the ice restart gears turning.
if (iceRestartPrimed) {
BeginIceRestart();
}
UpdateSignalingState();
pco->OnCreateAnswerSuccess(ObString(answer.c_str()), rv);
}
@ -1651,82 +1565,6 @@ PeerConnectionImpl::CreateAnswer()
return NS_OK;
}
nsresult
PeerConnectionImpl::SetupIceRestartCredentials()
{
if (mMedia->IsIceRestarting()) {
CSFLogError(LOGTAG, "%s: ICE already restarting",
__FUNCTION__);
return NS_ERROR_UNEXPECTED;
}
std::string ufrag = mMedia->ice_ctx()->GetNewUfrag();
std::string pwd = mMedia->ice_ctx()->GetNewPwd();
if (ufrag.empty() || pwd.empty()) {
CSFLogError(LOGTAG, "%s: Bad ICE credentials (ufrag:'%s'/pwd:'%s')",
__FUNCTION__,
ufrag.c_str(), pwd.c_str());
return NS_ERROR_UNEXPECTED;
}
// hold on to the current ice creds in case of rollback
mPreviousIceUfrag = mJsepSession->GetUfrag();
mPreviousIcePwd = mJsepSession->GetPwd();
nsresult nrv = mJsepSession->SetIceCredentials(ufrag, pwd);
if (NS_FAILED(nrv)) {
CSFLogError(LOGTAG, "%s: Couldn't set ICE credentials, res=%u",
__FUNCTION__,
static_cast<unsigned>(nrv));
return nrv;
}
return NS_OK;
}
void
PeerConnectionImpl::BeginIceRestart()
{
mMedia->BeginIceRestart(mJsepSession->GetUfrag(), mJsepSession->GetPwd());
}
nsresult
PeerConnectionImpl::ResetIceCredentials()
{
nsresult nrv = mJsepSession->SetIceCredentials(mPreviousIceUfrag, mPreviousIcePwd);
mPreviousIceUfrag = "";
mPreviousIcePwd = "";
if (NS_FAILED(nrv)) {
CSFLogError(LOGTAG, "%s: Couldn't reset ICE credentials, res=%u",
__FUNCTION__,
static_cast<unsigned>(nrv));
return nrv;
}
return NS_OK;
}
nsresult
PeerConnectionImpl::RollbackIceRestart()
{
mMedia->RollbackIceRestart();
++mIceRollbackCount;
// put back the previous ice creds
return ResetIceCredentials();
}
void
PeerConnectionImpl::FinalizeIceRestart()
{
mMedia->FinalizeIceRestart();
// clear the previous ice creds since they are no longer needed
mPreviousIceUfrag = "";
mPreviousIcePwd = "";
++mIceRestartCount;
}
NS_IMETHODIMP
PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP)
{
@ -1750,6 +1588,7 @@ PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP)
mLocalRequestedSDP = aSDP;
bool wasRestartingIce = mJsepSession->IsIceRestarting();
JsepSdpType sdpType;
switch (aAction) {
case IPeerConnection::kActionOffer:
@ -1789,6 +1628,9 @@ PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP)
__FUNCTION__, mHandle.c_str(), errorString.c_str());
pco->OnSetLocalDescriptionError(error, ObString(errorString.c_str()), rv);
} else {
if (wasRestartingIce) {
RecordIceRestartStatistics(sdpType);
}
UpdateSignalingState(sdpType == mozilla::kJsepSdpRollback);
pco->OnSetLocalDescriptionSuccess(rv);
}
@ -1849,6 +1691,7 @@ PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
STAMP_TIMECARD(mTimeCard, "Set Remote Description");
mRemoteRequestedSDP = aSDP;
bool wasRestartingIce = mJsepSession->IsIceRestarting();
JsepSdpType sdpType;
switch (action) {
case IPeerConnection::kActionOffer:
@ -1934,6 +1777,9 @@ PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
}
}
if (wasRestartingIce) {
RecordIceRestartStatistics(sdpType);
}
UpdateSignalingState(sdpType == mozilla::kJsepSdpRollback);
pco->OnSetRemoteDescriptionSuccess(jrv);
@ -2836,15 +2682,6 @@ PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState,
mSignalingState = aSignalingState;
if (mSignalingState == PCImplSignalingState::SignalingStable) {
if (mMedia->GetIceRestartState() ==
PeerConnectionMedia::ICE_RESTART_PROVISIONAL) {
if (rollback) {
RollbackIceRestart();
} else {
mMedia->CommitIceRestart();
}
}
// If we're rolling back a local offer, we might need to remove some
// transports, and stomp some MediaPipeline setup, but nothing further
// needs to be done.
@ -3125,14 +2962,6 @@ void PeerConnectionImpl::IceConnectionStateChange(
mIceConnectionState = domState;
if (mIceConnectionState == PCImplIceConnectionState::Connected ||
mIceConnectionState == PCImplIceConnectionState::Completed ||
mIceConnectionState == PCImplIceConnectionState::Failed) {
if (mMedia->IsIceRestarting()) {
FinalizeIceRestart();
}
}
// Uncount this connection as active on the inner window upon close.
if (mWindow && mActiveOnWindow && mIceConnectionState == PCImplIceConnectionState::Closed) {
mWindow->RemovePeerConnection();
@ -3726,6 +3555,22 @@ PeerConnectionImpl::RecordLongtermICEStatistics() {
WebrtcGlobalInformation::StoreLongTermICEStatistics(*this);
}
void
PeerConnectionImpl::RecordIceRestartStatistics(JsepSdpType type)
{
switch (type) {
case mozilla::kJsepSdpOffer:
case mozilla::kJsepSdpPranswer:
break;
case mozilla::kJsepSdpAnswer:
++mIceRestartCount;
break;
case mozilla::kJsepSdpRollback:
++mIceRollbackCount;
break;
}
}
void
PeerConnectionImpl::IceStreamReady(NrIceMediaStream *aStream)
{

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

@ -687,12 +687,6 @@ private:
dom::MediaStreamTrack* aSendTrack,
ErrorResult& aRv);
nsresult SetupIceRestartCredentials();
void BeginIceRestart();
nsresult ResetIceCredentials();
nsresult RollbackIceRestart();
void FinalizeIceRestart();
static void GetStatsForPCObserver_s(
const std::string& pcHandle,
nsAutoPtr<RTCStatsQuery> query);
@ -710,6 +704,8 @@ private:
// or other things.
void RecordLongtermICEStatistics();
void RecordIceRestartStatistics(JsepSdpType type);
// Timecard used to measure processing time. This should be the first class
// attribute so that we accurately measure the time required to instantiate
// any other attributes of this class.
@ -773,8 +769,6 @@ private:
// The JSEP negotiation session.
mozilla::UniquePtr<PCUuidGenerator> mUuidGen;
mozilla::UniquePtr<mozilla::JsepSession> mJsepSession;
std::string mPreviousIceUfrag; // used during rollback of ice restart
std::string mPreviousIcePwd; // used during rollback of ice restart
unsigned long mIceRestartCount;
unsigned long mIceRollbackCount;

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

@ -98,7 +98,7 @@ PeerConnectionMedia::ProtocolProxyQueryHandler::SetProxyOnPcm(
return;
}
if (pcm_->mIceCtxHdlr.get()) {
if (pcm_->mIceCtx.get()) {
assert(httpsProxyPort >= 0 && httpsProxyPort < (1 << 16));
// Note that this could check if PrivacyRequested() is set on the PC and
// remove "webrtc" from the ALPN list. But that would only work if the PC
@ -131,7 +131,7 @@ PeerConnectionMedia::StunAddrsHandler::OnStunAddrsAvailable(
// If parent process returns 0 STUN addresses, change ICE connection
// state to failed.
if (!pcm_->mStunAddrs.Length()) {
pcm_->SignalIceConnectionStateChange(pcm_->mIceCtxHdlr->ctx().get(),
pcm_->SignalIceConnectionStateChange(pcm_->mIceCtx.get(),
NrIceCtx::ICE_CTX_FAILED);
}
@ -143,13 +143,12 @@ PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
: mParent(parent),
mParentHandle(parent->GetHandle()),
mParentName(parent->GetName()),
mIceCtxHdlr(nullptr),
mIceCtx(nullptr),
mDNSResolver(new NrIceResolver()),
mUuidGen(MakeUnique<PCUuidGenerator>()),
mMainThread(mParent->GetMainThread()),
mSTSThread(mParent->GetSTSThread()),
mProxyResolveCompleted(false),
mIceRestartState(ICE_RESTART_NONE),
mLocalAddrsCompleted(false) {
}
@ -253,26 +252,26 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
// setup the stun local addresses IPC async call
InitLocalAddrs();
NrIceCtx::InitializeGlobals(mParent->GetAllowIceLoopback(),
ice_tcp,
mParent->GetAllowIceLinkLocal());
// TODO(ekr@rtfm.com): need some way to set not offerer later
// Looks like a bug in the NrIceCtx API.
mIceCtxHdlr = NrIceCtxHandler::Create("PC:" + mParentName,
mParent->GetAllowIceLoopback(),
ice_tcp,
mParent->GetAllowIceLinkLocal(),
policy);
if(!mIceCtxHdlr) {
mIceCtx = NrIceCtx::Create("PC:" + mParentName, policy);
if(!mIceCtx) {
CSFLogError(LOGTAG, "%s: Failed to create Ice Context", __FUNCTION__);
return NS_ERROR_FAILURE;
}
if (NS_FAILED(rv = mIceCtxHdlr->ctx()->SetStunServers(stun_servers))) {
if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) {
CSFLogError(LOGTAG, "%s: Failed to set stun servers", __FUNCTION__);
return rv;
}
// Give us a way to globally turn off TURN support
bool disabled = Preferences::GetBool("media.peerconnection.turn.disable", false);
if (!disabled) {
if (NS_FAILED(rv = mIceCtxHdlr->ctx()->SetTurnServers(turn_servers))) {
if (NS_FAILED(rv = mIceCtx->SetTurnServers(turn_servers))) {
CSFLogError(LOGTAG, "%s: Failed to set turn servers", __FUNCTION__);
return rv;
}
@ -284,11 +283,11 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
return rv;
}
if (NS_FAILED(rv =
mIceCtxHdlr->ctx()->SetResolver(mDNSResolver->AllocateResolver()))) {
mIceCtx->SetResolver(mDNSResolver->AllocateResolver()))) {
CSFLogError(LOGTAG, "%s: Failed to get dns resolver", __FUNCTION__);
return rv;
}
ConnectSignals(mIceCtxHdlr->ctx().get());
ConnectSignals(mIceCtx.get());
return NS_OK;
}
@ -303,6 +302,8 @@ PeerConnectionMedia::EnsureTransports(const JsepSession& aSession)
WrapRunnable(RefPtr<PeerConnectionMedia>(this),
&PeerConnectionMedia::EnsureTransport_s,
transceiver->mTransport.mTransportId,
transceiver->mTransport.mLocalUfrag,
transceiver->mTransport.mLocalPwd,
transceiver->mTransport.mComponents),
NS_DISPATCH_NORMAL);
}
@ -313,9 +314,11 @@ PeerConnectionMedia::EnsureTransports(const JsepSession& aSession)
void
PeerConnectionMedia::EnsureTransport_s(const std::string& aTransportId,
const std::string& aUfrag,
const std::string& aPwd,
size_t aComponentCount)
{
RefPtr<NrIceMediaStream> stream(mIceCtxHdlr->ctx()->GetStream(aTransportId));
RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId));
if (!stream) {
CSFLogDebug(LOGTAG, "%s: Creating ICE media stream=%s components=%u",
mParentHandle.c_str(),
@ -324,21 +327,21 @@ PeerConnectionMedia::EnsureTransport_s(const std::string& aTransportId,
std::ostringstream os;
os << mParentName << " transport-id=" << aTransportId;
RefPtr<NrIceMediaStream> stream =
mIceCtxHdlr->CreateStream(os.str(),
aComponentCount);
stream = mIceCtx->CreateStream(aTransportId,
os.str(),
aComponentCount);
if (!stream) {
CSFLogError(LOGTAG, "Failed to create ICE stream.");
return;
}
stream->SetId(aTransportId);
stream->SignalReady.connect(this, &PeerConnectionMedia::IceStreamReady_s);
stream->SignalCandidate.connect(this,
&PeerConnectionMedia::OnCandidateFound_s);
mIceCtxHdlr->ctx()->SetStream(aTransportId, stream);
}
// This might begin an ICE restart
stream->SetIceCredentials(aUfrag, aPwd);
}
nsresult
@ -406,6 +409,8 @@ PeerConnectionMedia::UpdateTransport(const JsepTransceiver& aTransceiver,
WrapRunnable(RefPtr<PeerConnectionMedia>(this),
&PeerConnectionMedia::ActivateTransport_s,
transport.mTransportId,
transport.mLocalUfrag,
transport.mLocalPwd,
components,
ufrag,
pwd,
@ -418,6 +423,8 @@ PeerConnectionMedia::UpdateTransport(const JsepTransceiver& aTransceiver,
void
PeerConnectionMedia::ActivateTransport_s(
const std::string& aTransportId,
const std::string& aLocalUfrag,
const std::string& aLocalPwd,
size_t aComponentCount,
const std::string& aUfrag,
const std::string& aPassword,
@ -425,36 +432,34 @@ PeerConnectionMedia::ActivateTransport_s(
MOZ_ASSERT(aComponentCount);
RefPtr<NrIceMediaStream> stream(mIceCtxHdlr->ctx()->GetStream(aTransportId));
RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId));
if (!stream) {
MOZ_ASSERT(false);
return;
}
if (!stream->HasParsedAttributes()) {
CSFLogDebug(LOGTAG, "%s: Activating ICE media stream=%s components=%u",
mParentHandle.c_str(),
aTransportId.c_str(),
static_cast<unsigned>(aComponentCount));
CSFLogDebug(LOGTAG, "%s: Activating ICE media stream=%s components=%u",
mParentHandle.c_str(),
aTransportId.c_str(),
static_cast<unsigned>(aComponentCount));
std::vector<std::string> attrs;
attrs.reserve(aCandidateList.size() + 2 /* ufrag + pwd */);
for (const auto& candidate : aCandidateList) {
attrs.push_back("candidate:" + candidate);
}
attrs.push_back("ice-ufrag:" + aUfrag);
attrs.push_back("ice-pwd:" + aPassword);
std::vector<std::string> attrs;
attrs.reserve(aCandidateList.size() + 2 /* ufrag + pwd */);
for (const auto& candidate : aCandidateList) {
attrs.push_back("candidate:" + candidate);
}
attrs.push_back("ice-ufrag:" + aUfrag);
attrs.push_back("ice-pwd:" + aPassword);
nsresult rv = stream->ParseAttributes(attrs);
if (NS_FAILED(rv)) {
CSFLogError(LOGTAG, "Couldn't parse ICE attributes, rv=%u",
static_cast<unsigned>(rv));
}
nsresult rv = stream->ConnectToPeer(aLocalUfrag, aLocalPwd, attrs);
if (NS_FAILED(rv)) {
CSFLogError(LOGTAG, "Couldn't parse ICE attributes, rv=%u",
static_cast<unsigned>(rv));
}
for (size_t c = aComponentCount; c < stream->components(); ++c) {
// components are 1-indexed
stream->DisableComponent(c + 1);
}
for (size_t c = aComponentCount; c < stream->components(); ++c) {
// components are 1-indexed
stream->DisableComponent(c + 1);
}
}
@ -462,9 +467,9 @@ void
PeerConnectionMedia::RemoveTransportsExcept_s(
const std::set<std::string>& aIds)
{
for (const auto& stream : mIceCtxHdlr->ctx()->GetStreams()) {
for (const auto& stream : mIceCtx->GetStreams()) {
if (!aIds.count(stream->GetId())) {
mIceCtxHdlr->ctx()->SetStream(stream->GetId(), nullptr);
mIceCtx->DestroyStream(stream->GetId());
}
}
}
@ -540,18 +545,6 @@ FinalizeTransportFlow_s(RefPtr<PeerConnectionMedia> aPCMedia,
aFlow->PushLayer(aSrtpLayer);
}
static void
AddNewIceStreamForRestart_s(RefPtr<PeerConnectionMedia> aPCMedia,
RefPtr<TransportFlow> aFlow,
const std::string& aTransportId,
bool aIsRtcp)
{
TransportLayerIce* ice =
static_cast<TransportLayerIce*>(aFlow->GetLayer("ice"));
ice->SetParameters(aPCMedia->ice_media_stream(aTransportId),
aIsRtcp ? 2 : 1);
}
nsresult
PeerConnectionMedia::UpdateTransportFlow(bool aIsRtcp,
const JsepTransport& aTransport)
@ -572,21 +565,6 @@ PeerConnectionMedia::UpdateTransportFlow(bool aIsRtcp,
RefPtr<TransportFlow> flow = GetTransportFlow(aTransport.mTransportId, aIsRtcp);
if (flow) {
if (IsIceRestarting()) {
CSFLogInfo(LOGTAG, "Flow[%s]: detected ICE restart - id: %s rtcp: %d",
flow->id().c_str(), aTransport.mTransportId.c_str(), aIsRtcp);
RefPtr<PeerConnectionMedia> pcMedia(this);
rv = GetSTSThread()->Dispatch(
WrapRunnableNM(AddNewIceStreamForRestart_s,
pcMedia, flow, aTransport.mTransportId, aIsRtcp),
NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
CSFLogError(LOGTAG, "Failed to dispatch AddNewIceStreamForRestart_s");
return rv;
}
}
return NS_OK;
}
@ -707,154 +685,16 @@ PeerConnectionMedia::StartIceChecks_s(
}
}
nsresult rv = mIceCtxHdlr->ctx()->ParseGlobalAttributes(attributes);
nsresult rv = mIceCtx->ParseGlobalAttributes(attributes);
if (NS_FAILED(rv)) {
CSFLogError(LOGTAG, "%s: couldn't parse global parameters", __FUNCTION__ );
}
mIceCtxHdlr->ctx()->SetControlling(aIsControlling ?
mIceCtx->SetControlling(aIsControlling ?
NrIceCtx::ICE_CONTROLLING :
NrIceCtx::ICE_CONTROLLED);
mIceCtxHdlr->ctx()->StartChecks(aIsOfferer);
}
bool
PeerConnectionMedia::IsIceRestarting() const
{
ASSERT_ON_THREAD(mMainThread);
return (mIceRestartState != ICE_RESTART_NONE);
}
PeerConnectionMedia::IceRestartState
PeerConnectionMedia::GetIceRestartState() const
{
ASSERT_ON_THREAD(mMainThread);
return mIceRestartState;
}
void
PeerConnectionMedia::BeginIceRestart(const std::string& ufrag,
const std::string& pwd)
{
ASSERT_ON_THREAD(mMainThread);
if (IsIceRestarting()) {
return;
}
RefPtr<NrIceCtx> new_ctx = mIceCtxHdlr->CreateCtx(ufrag, pwd);
RUN_ON_THREAD(GetSTSThread(),
WrapRunnable(
RefPtr<PeerConnectionMedia>(this),
&PeerConnectionMedia::BeginIceRestart_s,
new_ctx),
NS_DISPATCH_NORMAL);
mIceRestartState = ICE_RESTART_PROVISIONAL;
}
void
PeerConnectionMedia::BeginIceRestart_s(RefPtr<NrIceCtx> new_ctx)
{
ASSERT_ON_THREAD(mSTSThread);
// hold the original context so we can disconnect signals if needed
RefPtr<NrIceCtx> originalCtx = mIceCtxHdlr->ctx();
if (mIceCtxHdlr->BeginIceRestart(new_ctx)) {
ConnectSignals(mIceCtxHdlr->ctx().get(), originalCtx.get());
}
}
void
PeerConnectionMedia::CommitIceRestart()
{
ASSERT_ON_THREAD(mMainThread);
if (mIceRestartState != ICE_RESTART_PROVISIONAL) {
return;
}
mIceRestartState = ICE_RESTART_COMMITTED;
}
void
PeerConnectionMedia::FinalizeIceRestart()
{
ASSERT_ON_THREAD(mMainThread);
if (!IsIceRestarting()) {
return;
}
RUN_ON_THREAD(GetSTSThread(),
WrapRunnable(
RefPtr<PeerConnectionMedia>(this),
&PeerConnectionMedia::FinalizeIceRestart_s),
NS_DISPATCH_NORMAL);
mIceRestartState = ICE_RESTART_NONE;
}
void
PeerConnectionMedia::FinalizeIceRestart_s()
{
ASSERT_ON_THREAD(mSTSThread);
// reset old streams since we don't need them anymore
for (auto& transportFlow : mTransportFlows) {
RefPtr<TransportFlow> aFlow = transportFlow.second;
if (!aFlow) continue;
TransportLayerIce* ice =
static_cast<TransportLayerIce*>(aFlow->GetLayer(TransportLayerIce::ID()));
ice->ResetOldStream();
}
mIceCtxHdlr->FinalizeIceRestart();
}
void
PeerConnectionMedia::RollbackIceRestart()
{
ASSERT_ON_THREAD(mMainThread);
if (mIceRestartState != ICE_RESTART_PROVISIONAL) {
return;
}
RUN_ON_THREAD(GetSTSThread(),
WrapRunnable(
RefPtr<PeerConnectionMedia>(this),
&PeerConnectionMedia::RollbackIceRestart_s),
NS_DISPATCH_NORMAL);
mIceRestartState = ICE_RESTART_NONE;
}
void
PeerConnectionMedia::RollbackIceRestart_s()
{
ASSERT_ON_THREAD(mSTSThread);
// hold the restart context so we can disconnect signals
RefPtr<NrIceCtx> restartCtx = mIceCtxHdlr->ctx();
// restore old streams since we're rolling back
for (auto& transportFlow : mTransportFlows) {
RefPtr<TransportFlow> aFlow = transportFlow.second;
if (!aFlow) continue;
TransportLayerIce* ice =
static_cast<TransportLayerIce*>(aFlow->GetLayer(TransportLayerIce::ID()));
ice->RestoreOldStream();
}
mIceCtxHdlr->RollbackIceRestart();
ConnectSignals(mIceCtxHdlr->ctx().get(), restartCtx.get());
// Fixup the telemetry by transferring abandoned ctx stats to current ctx.
NrIceStats stats = restartCtx->Destroy();
restartCtx = nullptr;
mIceCtxHdlr->ctx()->AccumulateStats(stats);
mIceCtx->StartChecks(aIsOfferer);
}
bool
@ -926,7 +766,7 @@ PeerConnectionMedia::AddIceCandidate(const std::string& candidate,
void
PeerConnectionMedia::AddIceCandidate_s(const std::string& aCandidate,
const std::string& aTransportId) {
RefPtr<NrIceMediaStream> stream(mIceCtxHdlr->ctx()->GetStream(aTransportId));
RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId));
if (!stream) {
CSFLogError(LOGTAG, "No ICE stream for candidate with transport id %s: %s",
aTransportId.c_str(), aCandidate.c_str());
@ -954,7 +794,7 @@ PeerConnectionMedia::UpdateNetworkState(bool online) {
void
PeerConnectionMedia::UpdateNetworkState_s(bool online) {
mIceCtxHdlr->ctx()->UpdateNetworkState(online);
mIceCtx->UpdateNetworkState(online);
}
void
@ -999,9 +839,9 @@ void
PeerConnectionMedia::EnsureIceGathering_s(bool aDefaultRouteOnly,
bool aProxyOnly) {
if (mProxyServer) {
mIceCtxHdlr->ctx()->SetProxyServer(*mProxyServer);
mIceCtx->SetProxyServer(*mProxyServer);
} else if (aProxyOnly) {
IceGatheringStateChange_s(mIceCtxHdlr->ctx().get(),
IceGatheringStateChange_s(mIceCtx.get(),
NrIceCtx::ICE_CTX_GATHER_COMPLETE);
return;
}
@ -1022,15 +862,15 @@ PeerConnectionMedia::EnsureIceGathering_s(bool aDefaultRouteOnly,
// needs to have the proper flags set on ice ctx. For non-e10s,
// setting those flags happens in StartGathering. We could probably
// just set them here, and only do it here.
mIceCtxHdlr->ctx()->SetCtxFlags(aDefaultRouteOnly, aProxyOnly);
mIceCtx->SetCtxFlags(aDefaultRouteOnly, aProxyOnly);
if (mStunAddrs.Length()) {
mIceCtxHdlr->ctx()->SetStunAddrs(mStunAddrs);
mIceCtx->SetStunAddrs(mStunAddrs);
}
// Start gathering, but only if there are streams
if (!mIceCtxHdlr->ctx()->GetStreams().empty()) {
mIceCtxHdlr->ctx()->StartGathering(aDefaultRouteOnly, aProxyOnly);
if (!mIceCtx->GetStreams().empty()) {
mIceCtx->StartGathering(aDefaultRouteOnly, aProxyOnly);
return;
}
@ -1040,7 +880,7 @@ PeerConnectionMedia::EnsureIceGathering_s(bool aDefaultRouteOnly,
// If there are no streams, we're probably in a situation where we've rolled
// back while still waiting for our proxy configuration to come back. Make
// sure content knows that the rollback has stuck wrt gathering.
IceGatheringStateChange_s(mIceCtxHdlr->ctx().get(),
IceGatheringStateChange_s(mIceCtx.get(),
NrIceCtx::ICE_CTX_GATHER_COMPLETE);
}
@ -1103,7 +943,7 @@ PeerConnectionMedia::ShutdownMediaTransport_s()
mTransportFlows.clear();
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
NrIceStats stats = mIceCtxHdlr->Destroy();
NrIceStats stats = mIceCtx->Destroy();
CSFLogDebug(LOGTAG, "Ice Telemetry: stun (retransmits: %d)"
" turn (401s: %d 403s: %d 438s: %d)",
@ -1120,7 +960,7 @@ PeerConnectionMedia::ShutdownMediaTransport_s()
stats.turn_438s);
#endif
mIceCtxHdlr = nullptr;
mIceCtx = nullptr;
// we're holding a ref to 'this' that's released by SelfDestruct_m
mMainThread->Dispatch(WrapRunnable(this, &PeerConnectionMedia::SelfDestruct_m),
@ -1293,7 +1133,7 @@ PeerConnectionMedia::OnCandidateFound_s(NrIceMediaStream *aStream,
ASSERT_ON_THREAD(mSTSThread);
MOZ_ASSERT(aStream);
MOZ_ASSERT(!aStream->GetId().empty());
MOZ_RELEASE_ASSERT(mIceCtxHdlr);
MOZ_RELEASE_ASSERT(mIceCtx);
CSFLogDebug(LOGTAG, "%s: %s", __FUNCTION__, aStream->name().c_str());

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

@ -28,7 +28,6 @@ class MediaStreamTrack;
}
}
#include "nricectxhandler.h"
#include "nriceresolver.h"
#include "nricemediastream.h"
@ -50,11 +49,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
public:
explicit PeerConnectionMedia(PeerConnectionImpl *parent);
enum IceRestartState { ICE_RESTART_NONE,
ICE_RESTART_PROVISIONAL,
ICE_RESTART_COMMITTED
};
PeerConnectionImpl* GetPC() { return mParent; }
nsresult Init(const std::vector<NrIceStunServer>& stun_servers,
const std::vector<NrIceTurnServer>& turn_servers,
@ -62,12 +56,11 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// WARNING: This destroys the object!
void SelfDestruct();
RefPtr<NrIceCtxHandler> ice_ctx_hdlr() const { return mIceCtxHdlr; }
RefPtr<NrIceCtx> ice_ctx() const { return mIceCtxHdlr->ctx(); }
RefPtr<NrIceCtx> ice_ctx() const { return mIceCtx; }
RefPtr<NrIceMediaStream> ice_media_stream(
const std::string& aTransportId) const {
return mIceCtxHdlr->ctx()->GetStream(aTransportId);
return mIceCtx->GetStream(aTransportId);
}
// Ensure ICE transports exist that we might need when offer/answer concludes
@ -81,19 +74,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// Start ICE checks.
void StartIceChecks(const JsepSession& session);
bool IsIceRestarting() const;
IceRestartState GetIceRestartState() const;
// Begin ICE restart
void BeginIceRestart(const std::string& ufrag,
const std::string& pwd);
// Commit ICE Restart - offer/answer complete, no rollback possible
void CommitIceRestart();
// Finalize ICE restart
void FinalizeIceRestart();
// Abort ICE restart
void RollbackIceRestart();
// Process a trickle ICE candidate.
void AddIceCandidate(const std::string& candidate,
const std::string& aTransportId);
@ -240,8 +220,12 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
bool aForceIceTcp);
void EnsureTransport_s(const std::string& aTransportId,
const std::string& aUfrag,
const std::string& aPwd,
size_t aComponentCount);
void ActivateTransport_s(const std::string& aTransportId,
const std::string& aLocalUfrag,
const std::string& aLocalPwd,
size_t aComponentCount,
const std::string& aUfrag,
const std::string& aPassword,
@ -260,9 +244,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
bool aIsIceLite,
const std::vector<std::string>& aIceOptionsList);
void BeginIceRestart_s(RefPtr<NrIceCtx> new_ctx);
void FinalizeIceRestart_s();
void RollbackIceRestart_s();
bool GetPrefDefaultAddressOnly() const;
bool GetPrefProxyOnly() const;
@ -319,7 +300,7 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
std::vector<RefPtr<TransceiverImpl>> mTransceivers;
// ICE objects
RefPtr<NrIceCtxHandler> mIceCtxHdlr;
RefPtr<NrIceCtx> mIceCtx;
// DNS
RefPtr<NrIceResolver> mDNSResolver;
@ -354,9 +335,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// Used to store the result of the request.
UniquePtr<NrIceProxyServer> mProxyServer;
// Used to track the state of ice restart
IceRestartState mIceRestartState;
// Used to cancel incoming stun addrs response
RefPtr<net::StunAddrsRequestChild> mStunAddrsRequest;