зеркало из https://github.com/mozilla/gecko-dev.git
Bug 842549 - Part 1. Generate trickle candidates from nICEr, with testing r=abr
This commit is contained in:
Родитель
c83409e3af
Коммит
42a2151002
|
@ -252,7 +252,7 @@ int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream,
|
|||
int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) {
|
||||
MOZ_MTLOG(ML_DEBUG, "stream_ready called");
|
||||
|
||||
// Get the ICE ctx
|
||||
// Get the ICE ctx.
|
||||
NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
|
||||
|
||||
RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
|
||||
|
@ -306,6 +306,30 @@ int NrIceCtx::msg_recvd(void *obj, nr_ice_peer_ctx *pctx,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx,
|
||||
nr_ice_media_stream *stream,
|
||||
int component_id,
|
||||
nr_ice_candidate *candidate) {
|
||||
// Get the ICE ctx
|
||||
NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
|
||||
RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
|
||||
|
||||
// Streams which do not exist shouldn't have candidates.
|
||||
MOZ_ASSERT(s);
|
||||
|
||||
// Format the candidate.
|
||||
char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE];
|
||||
int r = nr_ice_format_candidate_attribute(candidate, candidate_str,
|
||||
sizeof(candidate_str));
|
||||
MOZ_ASSERT(!r);
|
||||
if (r)
|
||||
return;
|
||||
|
||||
MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate "
|
||||
<< candidate_str);
|
||||
|
||||
s->SignalCandidate(s, candidate_str);
|
||||
}
|
||||
|
||||
RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
|
||||
bool offerer,
|
||||
|
@ -383,6 +407,14 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
|
|||
}
|
||||
#endif // USE_INTERFACE_PRIORITIZER
|
||||
|
||||
if (ctx->generating_trickle()) {
|
||||
r = nr_ice_ctx_set_trickle_cb(ctx->ctx_, &NrIceCtx::trickle_cb, ctx);
|
||||
if (r) {
|
||||
MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name << "'");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the handler objects
|
||||
ctx->ice_handler_vtbl_ = new nr_ice_handler_vtbl();
|
||||
ctx->ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair;
|
||||
|
@ -535,15 +567,6 @@ nsresult NrIceCtx::StartGathering() {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void NrIceCtx::EmitAllCandidates() {
|
||||
MOZ_MTLOG(ML_NOTICE, "Gathered all ICE candidates for '"
|
||||
<< name_ << "'");
|
||||
|
||||
for(size_t i=0; i<streams_.size(); ++i) {
|
||||
streams_[i]->EmitAllCandidates();
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<NrIceMediaStream> NrIceCtx::FindStream(
|
||||
nr_ice_media_stream *stream) {
|
||||
for (size_t i=0; i<streams_.size(); ++i) {
|
||||
|
@ -630,8 +653,6 @@ nsresult NrIceCtx::StartChecks() {
|
|||
void NrIceCtx::initialized_cb(NR_SOCKET s, int h, void *arg) {
|
||||
NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
|
||||
|
||||
ctx->EmitAllCandidates();
|
||||
|
||||
ctx->SetState(ICE_CTX_GATHERED);
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx;
|
|||
typedef struct nr_ice_media_stream_ nr_ice_media_stream;
|
||||
typedef struct nr_ice_handler_ nr_ice_handler;
|
||||
typedef struct nr_ice_handler_vtbl_ nr_ice_handler_vtbl;
|
||||
typedef struct nr_ice_candidate_ nr_ice_candidate;
|
||||
typedef struct nr_ice_cand_pair_ nr_ice_cand_pair;
|
||||
typedef struct nr_ice_stun_server_ nr_ice_stun_server;
|
||||
typedef struct nr_ice_turn_server_ nr_ice_turn_server;
|
||||
|
@ -221,6 +222,9 @@ class NrIceCtx {
|
|||
// more forking.
|
||||
nsresult Finalize();
|
||||
|
||||
// Are we trickling?
|
||||
bool generating_trickle() const { return trickle_; }
|
||||
|
||||
// Signals to indicate events. API users can (and should)
|
||||
// register for these.
|
||||
// TODO(ekr@rtfm.com): refactor this to be state change instead
|
||||
|
@ -244,8 +248,8 @@ class NrIceCtx {
|
|||
ctx_(nullptr),
|
||||
peer_(nullptr),
|
||||
ice_handler_vtbl_(nullptr),
|
||||
ice_handler_(nullptr)
|
||||
{
|
||||
ice_handler_(nullptr),
|
||||
trickle_(true) {
|
||||
// XXX: offerer_ will be used eventually; placate clang in the meantime.
|
||||
(void)offerer_;
|
||||
}
|
||||
|
@ -265,10 +269,8 @@ class NrIceCtx {
|
|||
static int msg_recvd(void *obj, nr_ice_peer_ctx *pctx,
|
||||
nr_ice_media_stream *stream, int component_id,
|
||||
unsigned char *msg, int len);
|
||||
|
||||
// Iterate through all media streams and emit the candidates
|
||||
// Note that we don't do trickle ICE yet
|
||||
void EmitAllCandidates();
|
||||
static void trickle_cb(void *arg, nr_ice_ctx *ctx, nr_ice_media_stream *stream,
|
||||
int component_id, nr_ice_candidate *candidate);
|
||||
|
||||
// Find a media stream by stream ptr. Gross
|
||||
RefPtr<NrIceMediaStream> FindStream(nr_ice_media_stream *stream);
|
||||
|
@ -284,6 +286,7 @@ class NrIceCtx {
|
|||
nr_ice_peer_ctx *peer_;
|
||||
nr_ice_handler_vtbl* ice_handler_vtbl_; // Must be pointer
|
||||
nr_ice_handler* ice_handler_; // Must be pointer
|
||||
bool trickle_;
|
||||
nsCOMPtr<nsIEventTarget> sts_target_; // The thread to run on
|
||||
};
|
||||
|
||||
|
|
|
@ -243,26 +243,6 @@ nsresult NrIceMediaStream::GetActivePair(int component,
|
|||
}
|
||||
|
||||
|
||||
void NrIceMediaStream::EmitAllCandidates() {
|
||||
char **attrs = 0;
|
||||
int attrct;
|
||||
int r;
|
||||
r = nr_ice_media_stream_get_attributes(stream_,
|
||||
&attrs, &attrct);
|
||||
if (r) {
|
||||
MOZ_MTLOG(ML_ERROR, "Couldn't get ICE candidates for '"
|
||||
<< name_ << "'");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0; i<attrct; i++) {
|
||||
SignalCandidate(this, attrs[i]);
|
||||
RFREE(attrs[i]);
|
||||
}
|
||||
|
||||
RFREE(attrs);
|
||||
}
|
||||
|
||||
nsresult NrIceMediaStream::GetCandidatePairs(std::vector<NrIceCandidatePair>*
|
||||
out_pairs) const {
|
||||
MOZ_ASSERT(out_pairs);
|
||||
|
@ -332,23 +312,35 @@ nsresult NrIceMediaStream::GetDefaultCandidate(int component,
|
|||
r = nr_ice_media_stream_get_default_candidate(stream_,
|
||||
component, &cand);
|
||||
if (r) {
|
||||
MOZ_MTLOG(ML_ERROR, "Couldn't get default ICE candidate for '"
|
||||
<< name_ << "'");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
if (ctx_->generating_trickle()) {
|
||||
// Generate default trickle candidates.
|
||||
// draft-ivov-mmusic-trickle-ice-01.txt says to use port 9
|
||||
// but "::" instead of "0.0.0.0". Since we don't do any
|
||||
// IPv6 we are ignoring that for now.
|
||||
*addrp = "0.0.0.0";
|
||||
*portp = 9;
|
||||
}
|
||||
else {
|
||||
MOZ_MTLOG(ML_ERROR, "Couldn't get default ICE candidate for '"
|
||||
<< name_ << "'");
|
||||
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
char addr[64]; // Enough for IPv6 with colons.
|
||||
r = nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr));
|
||||
if (r)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
char addr[64]; // Enough for IPv6 with colons.
|
||||
r = nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr));
|
||||
if (r)
|
||||
return NS_ERROR_FAILURE;
|
||||
int port;
|
||||
r=nr_transport_addr_get_port(&cand->addr,&port);
|
||||
if (r)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
int port;
|
||||
r=nr_transport_addr_get_port(&cand->addr,&port);
|
||||
if (r)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*addrp = addr;
|
||||
*portp = port;
|
||||
*addrp = addr;
|
||||
*portp = port;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -106,6 +106,12 @@ struct NrIceCandidatePair {
|
|||
// TODO(bcampen@mozilla.com): Is it important to put the foundation in here?
|
||||
};
|
||||
|
||||
// Abstract base class for opaque values.
|
||||
class NrIceOpaque {
|
||||
public:
|
||||
virtual ~NrIceOpaque() {}
|
||||
};
|
||||
|
||||
class NrIceMediaStream {
|
||||
public:
|
||||
static RefPtr<NrIceMediaStream> Create(NrIceCtx *ctx,
|
||||
|
@ -164,6 +170,12 @@ class NrIceMediaStream {
|
|||
// the context has been destroyed.
|
||||
void Close();
|
||||
|
||||
// Set an opaque value. Owned by the media stream.
|
||||
void SetOpaque(NrIceOpaque *opaque) { opaque_ = opaque; }
|
||||
|
||||
// Get the opaque
|
||||
NrIceOpaque* opaque() const { return opaque_; }
|
||||
|
||||
sigslot::signal2<NrIceMediaStream *, const std::string& >
|
||||
SignalCandidate; // A new ICE candidate:
|
||||
sigslot::signal1<NrIceMediaStream *> SignalReady; // Candidate pair ready.
|
||||
|
@ -171,10 +183,6 @@ class NrIceMediaStream {
|
|||
sigslot::signal4<NrIceMediaStream *, int, const unsigned char *, int>
|
||||
SignalPacketReceived; // Incoming packet
|
||||
|
||||
// Emit all the ICE candidates. Note that this doesn't
|
||||
// work for trickle ICE yet--called internally
|
||||
void EmitAllCandidates();
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceMediaStream)
|
||||
|
||||
private:
|
||||
|
@ -184,7 +192,8 @@ class NrIceMediaStream {
|
|||
ctx_(ctx),
|
||||
name_(name),
|
||||
components_(components),
|
||||
stream_(nullptr) {}
|
||||
stream_(nullptr),
|
||||
opaque_(nullptr) {}
|
||||
|
||||
DISALLOW_COPY_ASSIGN(NrIceMediaStream);
|
||||
|
||||
|
@ -193,6 +202,7 @@ class NrIceMediaStream {
|
|||
const std::string name_;
|
||||
const int components_;
|
||||
nr_ice_media_stream *stream_;
|
||||
ScopedDeletePtr<NrIceOpaque> opaque_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -54,13 +54,16 @@ const uint16_t kDefaultStunServerPort=3478;
|
|||
const std::string kBogusIceCandidate(
|
||||
(char *)"candidate:0 2 UDP 2113601790 192.168.178.20 50769 typ");
|
||||
|
||||
std::string g_stun_server_address(kDefaultStunServerAddress);
|
||||
std::string g_stun_server_hostname(kDefaultStunServerHostname);
|
||||
std::string g_turn_server;
|
||||
std::string g_turn_user;
|
||||
std::string g_turn_password;
|
||||
|
||||
namespace {
|
||||
|
||||
enum TrickleMode { TRICKLE_NONE, TRICKLE_DEFERRED };
|
||||
enum TrickleMode { TRICKLE_NONE, TRICKLE_SIMULATE, TRICKLE_REAL };
|
||||
|
||||
typedef bool (*CandidateFilter)(const std::string& candidate);
|
||||
|
||||
static bool IsRelayCandidate(const std::string& candidate) {
|
||||
|
@ -128,7 +131,9 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
remote_(nullptr),
|
||||
candidate_filter_(nullptr),
|
||||
expected_local_type_(NrIceCandidate::ICE_HOST),
|
||||
expected_remote_type_(NrIceCandidate::ICE_HOST) {
|
||||
expected_remote_type_(NrIceCandidate::ICE_HOST),
|
||||
trickle_mode_(TRICKLE_NONE),
|
||||
trickled_(0) {
|
||||
ice_ctx_->SignalGatheringCompleted.connect(this,
|
||||
&IceTestPeer::GatheringComplete);
|
||||
ice_ctx_->SignalCompleted.connect(this, &IceTestPeer::IceCompleted);
|
||||
|
@ -154,7 +159,7 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
|
||||
ASSERT_TRUE(stream);
|
||||
streams_.push_back(stream);
|
||||
stream->SignalCandidate.connect(this, &IceTestPeer::GotCandidate);
|
||||
stream->SignalCandidate.connect(this, &IceTestPeer::CandidateInitialized);
|
||||
stream->SignalReady.connect(this, &IceTestPeer::StreamReady);
|
||||
stream->SignalFailed.connect(this, &IceTestPeer::StreamFailed);
|
||||
stream->SignalPacketReceived.connect(this, &IceTestPeer::PacketReceived);
|
||||
|
@ -189,11 +194,11 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
void SetFakeResolver() {
|
||||
ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
|
||||
PRNetAddr addr;
|
||||
PRStatus status = PR_StringToNetAddr(kDefaultStunServerAddress.c_str(),
|
||||
&addr);
|
||||
PRStatus status = PR_StringToNetAddr(g_stun_server_address.c_str(),
|
||||
&addr);
|
||||
addr.inet.port = kDefaultStunServerPort;
|
||||
ASSERT_EQ(PR_SUCCESS, status);
|
||||
fake_resolver_.SetAddr(kDefaultStunServerHostname, addr);
|
||||
fake_resolver_.SetAddr(g_stun_server_hostname, addr);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
|
||||
fake_resolver_.AllocateResolver())));
|
||||
}
|
||||
|
@ -219,7 +224,18 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
return ice_ctx_->GetGlobalAttributes();
|
||||
}
|
||||
|
||||
std::vector<std::string> GetCandidates(size_t stream) {
|
||||
std::vector<std::string> GetCandidates(size_t stream) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
RUN_ON_THREAD(
|
||||
test_utils->sts_target(),
|
||||
WrapRunnableRet(this, &IceTestPeer::GetCandidates_s, stream, &v),
|
||||
NS_DISPATCH_SYNC);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetCandidates_s(size_t stream) {
|
||||
std::vector<std::string> candidates;
|
||||
|
||||
if (stream >= streams_.size())
|
||||
|
@ -239,7 +255,8 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
return candidates;
|
||||
}
|
||||
|
||||
void SetExpectedTypes(NrIceCandidate::Type local, NrIceCandidate::Type remote) {
|
||||
void SetExpectedTypes(NrIceCandidate::Type local,
|
||||
NrIceCandidate::Type remote) {
|
||||
expected_local_type_ = local;
|
||||
expected_remote_type_ = remote;
|
||||
}
|
||||
|
@ -254,46 +271,53 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
size_t sent() { return sent_; }
|
||||
|
||||
// Start connecting to another peer
|
||||
void Connect(IceTestPeer *remote, TrickleMode trickle_mode,
|
||||
bool start = true) {
|
||||
void Connect_s(IceTestPeer *remote, TrickleMode trickle_mode,
|
||||
bool start = true) {
|
||||
nsresult res;
|
||||
|
||||
remote_ = remote;
|
||||
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnableRet(ice_ctx_,
|
||||
&NrIceCtx::ParseGlobalAttributes, remote->GetGlobalAttributes(), &res),
|
||||
NS_DISPATCH_SYNC);
|
||||
trickle_mode_ = trickle_mode;
|
||||
res = ice_ctx_->ParseGlobalAttributes(remote->GetGlobalAttributes());
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
|
||||
if (trickle_mode == TRICKLE_NONE) {
|
||||
if (trickle_mode == TRICKLE_NONE ||
|
||||
trickle_mode == TRICKLE_REAL) {
|
||||
for (size_t i=0; i<streams_.size(); ++i) {
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnableRet(streams_[i], &NrIceMediaStream::ParseAttributes,
|
||||
remote->GetCandidates(i),
|
||||
&res), NS_DISPATCH_SYNC);
|
||||
std::vector<std::string> candidates =
|
||||
remote->GetCandidates(i);
|
||||
|
||||
for (size_t j=0; j<candidates.size(); ++j) {
|
||||
std::cerr << "Candidate: " + candidates[j] << std::endl;
|
||||
}
|
||||
res = streams_[i]->ParseAttributes(candidates);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
}
|
||||
} else {
|
||||
// Parse empty attributes and then trickle them out later
|
||||
for (size_t i=0; i<streams_.size(); ++i) {
|
||||
std::vector<std::string> empty_attrs;
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnableRet(streams_[i], &NrIceMediaStream::ParseAttributes,
|
||||
empty_attrs,
|
||||
&res), NS_DISPATCH_SYNC);
|
||||
|
||||
res = streams_[i]->ParseAttributes(empty_attrs);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
}
|
||||
}
|
||||
|
||||
if (start) {
|
||||
StartChecks();
|
||||
// Now start checks
|
||||
res = ice_ctx_->StartChecks();
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
}
|
||||
}
|
||||
|
||||
void DoTrickle(size_t stream) {
|
||||
void Connect(IceTestPeer *remote, TrickleMode trickle_mode,
|
||||
bool start = true) {
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnable(
|
||||
this, &IceTestPeer::Connect_s, remote, trickle_mode, start),
|
||||
NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
void SimulateTrickle(size_t stream) {
|
||||
std::cerr << "Doing trickle for stream " << stream << std::endl;
|
||||
// If we are in trickle deferred mode, now trickle in the candidates
|
||||
// for |stream}
|
||||
|
@ -392,12 +416,41 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
|
||||
// Handle events
|
||||
void GatheringComplete(NrIceCtx *ctx) {
|
||||
std::cerr << "Gathering complete for " << name_ << std::endl;
|
||||
gathering_complete_ = true;
|
||||
|
||||
std::cerr << "CANDIDATES:" << std::endl;
|
||||
for (size_t i=0; i<streams_.size(); ++i) {
|
||||
std::cerr << "Stream " << name_ << std::endl;
|
||||
std::vector<std::string> candidates =
|
||||
streams_[i]->GetCandidates();
|
||||
|
||||
for(size_t j=0; j<candidates.size(); ++j) {
|
||||
std::cerr << candidates[j] << std::endl;
|
||||
}
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
}
|
||||
|
||||
void GotCandidate(NrIceMediaStream *stream, const std::string &candidate) {
|
||||
std::cerr << "Got candidate " << candidate << std::endl;
|
||||
void CandidateInitialized(NrIceMediaStream *stream, const std::string &candidate) {
|
||||
std::cerr << "Candidate initialized: " << candidate << std::endl;
|
||||
candidates_[stream->name()].push_back(candidate);
|
||||
|
||||
// If we are connected, then try to trickle to the
|
||||
// other side.
|
||||
if (remote_ && remote_->remote_) {
|
||||
std::vector<mozilla::RefPtr<NrIceMediaStream> >::iterator it =
|
||||
std::find(streams_.begin(), streams_.end(), stream);
|
||||
ASSERT_NE(streams_.end(), it);
|
||||
size_t index = it - streams_.begin();
|
||||
|
||||
ASSERT_GT(remote_->streams_.size(), index);
|
||||
nsresult res = remote_->streams_[index]->ParseTrickleCandidate(
|
||||
candidate);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
++trickled_;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult GetCandidatePairs(size_t stream_index,
|
||||
|
@ -570,6 +623,8 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
}
|
||||
|
||||
int trickled() { return trickled_; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
nsRefPtr<NrIceCtx> ice_ctx_;
|
||||
|
@ -586,6 +641,8 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
CandidateFilter candidate_filter_;
|
||||
NrIceCandidate::Type expected_local_type_;
|
||||
NrIceCandidate::Type expected_remote_type_;
|
||||
TrickleMode trickle_mode_;
|
||||
int trickled_;
|
||||
};
|
||||
|
||||
class IceGatherTest : public ::testing::Test {
|
||||
|
@ -598,9 +655,15 @@ class IceGatherTest : public ::testing::Test {
|
|||
peer_->AddStream(1);
|
||||
}
|
||||
|
||||
void Gather() {
|
||||
peer_->Gather();
|
||||
void Gather(bool wait = true) {
|
||||
peer_->Gather();
|
||||
|
||||
if (wait) {
|
||||
WaitForGather();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForGather() {
|
||||
ASSERT_TRUE_WAIT(peer_->gathering_complete(), 10000);
|
||||
}
|
||||
|
||||
|
@ -655,18 +718,19 @@ class IceConnectTest : public ::testing::Test {
|
|||
|
||||
bool Gather(bool wait) {
|
||||
Init(false);
|
||||
p1_->SetStunServer(kDefaultStunServerAddress, kDefaultStunServerPort);
|
||||
p2_->SetStunServer(kDefaultStunServerAddress, kDefaultStunServerPort);
|
||||
p1_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
|
||||
p2_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
|
||||
p1_->Gather();
|
||||
p2_->Gather();
|
||||
|
||||
EXPECT_TRUE_WAIT(p1_->gathering_complete(), 10000);
|
||||
if (!p1_->gathering_complete())
|
||||
return false;
|
||||
EXPECT_TRUE_WAIT(p2_->gathering_complete(), 10000);
|
||||
if (!p2_->gathering_complete())
|
||||
return false;
|
||||
|
||||
if (wait) {
|
||||
EXPECT_TRUE_WAIT(p1_->gathering_complete(), 10000);
|
||||
if (!p1_->gathering_complete())
|
||||
return false;
|
||||
EXPECT_TRUE_WAIT(p2_->gathering_complete(), 10000);
|
||||
if (!p2_->gathering_complete())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -720,24 +784,29 @@ class IceConnectTest : public ::testing::Test {
|
|||
ASSERT_TRUE_WAIT(p1_->ice_complete() && p2_->ice_complete(), 5000);
|
||||
}
|
||||
|
||||
void ConnectTrickle() {
|
||||
p1_->Connect(p2_, TRICKLE_DEFERRED);
|
||||
p2_->Connect(p1_, TRICKLE_DEFERRED);
|
||||
void WaitForGather() {
|
||||
ASSERT_TRUE_WAIT(p1_->gathering_complete(), 10000);
|
||||
ASSERT_TRUE_WAIT(p2_->gathering_complete(), 10000);
|
||||
}
|
||||
|
||||
void DoTrickle(size_t stream) {
|
||||
p1_->DoTrickle(stream);
|
||||
p2_->DoTrickle(stream);
|
||||
void ConnectTrickle(TrickleMode trickle = TRICKLE_SIMULATE) {
|
||||
p1_->Connect(p2_, trickle);
|
||||
p2_->Connect(p1_, trickle);
|
||||
}
|
||||
|
||||
void SimulateTrickle(size_t stream) {
|
||||
p1_->SimulateTrickle(stream);
|
||||
p2_->SimulateTrickle(stream);
|
||||
ASSERT_TRUE_WAIT(p1_->is_ready(stream), 5000);
|
||||
ASSERT_TRUE_WAIT(p2_->is_ready(stream), 5000);
|
||||
}
|
||||
|
||||
void DoTrickleP1(size_t stream) {
|
||||
p1_->DoTrickle(stream);
|
||||
void SimulateTrickleP1(size_t stream) {
|
||||
p1_->SimulateTrickle(stream);
|
||||
}
|
||||
|
||||
void DoTrickleP2(size_t stream) {
|
||||
p2_->DoTrickle(stream);
|
||||
void SimulateTrickleP2(size_t stream) {
|
||||
p2_->SimulateTrickle(stream);
|
||||
}
|
||||
|
||||
void VerifyConnected() {
|
||||
|
@ -828,18 +897,18 @@ class PrioritizerTest : public ::testing::Test {
|
|||
} // end namespace
|
||||
|
||||
TEST_F(IceGatherTest, TestGatherFakeStunServerHostnameNoResolver) {
|
||||
peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort);
|
||||
peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
|
||||
Gather();
|
||||
}
|
||||
|
||||
TEST_F(IceGatherTest, TestGatherFakeStunServerIpAddress) {
|
||||
peer_->SetStunServer(kDefaultStunServerAddress, kDefaultStunServerPort);
|
||||
peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
|
||||
peer_->SetFakeResolver();
|
||||
Gather();
|
||||
}
|
||||
|
||||
TEST_F(IceGatherTest, TestGatherFakeStunServerHostname) {
|
||||
peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort);
|
||||
peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
|
||||
peer_->SetFakeResolver();
|
||||
Gather();
|
||||
}
|
||||
|
@ -851,14 +920,14 @@ TEST_F(IceGatherTest, TestGatherFakeStunBogusHostname) {
|
|||
}
|
||||
|
||||
TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddress) {
|
||||
peer_->SetStunServer(kDefaultStunServerAddress, kDefaultStunServerPort);
|
||||
peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
|
||||
peer_->SetDNSResolver();
|
||||
Gather();
|
||||
// TODO(jib@mozilla.com): ensure we get server reflexive candidates Bug 848094
|
||||
}
|
||||
|
||||
TEST_F(IceGatherTest, TestGatherDNSStunServerHostname) {
|
||||
peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort);
|
||||
peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
|
||||
peer_->SetDNSResolver();
|
||||
Gather();
|
||||
}
|
||||
|
@ -923,6 +992,16 @@ TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddr) {
|
|||
ASSERT_FALSE(StreamHasMatchingCandidate(0, " 127.0.0.133 "));
|
||||
}
|
||||
|
||||
TEST_F(IceGatherTest, TestStunServerTrickle) {
|
||||
UseFakeStunServerWithResponse("192.0.2.1", 3333);
|
||||
TestStunServer::GetInstance()->SetActive(false);
|
||||
Gather(false);
|
||||
ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1"));
|
||||
TestStunServer::GetInstance()->SetActive(true);
|
||||
WaitForGather();
|
||||
ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1"));
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestGather) {
|
||||
AddStream("first", 1);
|
||||
ASSERT_TRUE(Gather(true));
|
||||
|
@ -970,8 +1049,8 @@ TEST_F(IceConnectTest, TestConnectP2ThenP1Trickle) {
|
|||
ASSERT_TRUE(Gather(true));
|
||||
ConnectP2();
|
||||
PR_Sleep(1000);
|
||||
ConnectP1(TRICKLE_DEFERRED);
|
||||
DoTrickleP1(0);
|
||||
ConnectP1(TRICKLE_SIMULATE);
|
||||
SimulateTrickleP1(0);
|
||||
WaitForComplete();
|
||||
}
|
||||
|
||||
|
@ -981,12 +1060,12 @@ TEST_F(IceConnectTest, TestConnectP2ThenP1TrickleTwoComponents) {
|
|||
ASSERT_TRUE(Gather(true));
|
||||
ConnectP2();
|
||||
PR_Sleep(1000);
|
||||
ConnectP1(TRICKLE_DEFERRED);
|
||||
DoTrickleP1(0);
|
||||
ConnectP1(TRICKLE_SIMULATE);
|
||||
SimulateTrickleP1(0);
|
||||
std::cerr << "Sleeping between trickle streams" << std::endl;
|
||||
PR_Sleep(1000); // Give this some time to settle but not complete
|
||||
// all of ICE.
|
||||
DoTrickleP1(1);
|
||||
SimulateTrickleP1(1);
|
||||
WaitForComplete(2);
|
||||
}
|
||||
|
||||
|
@ -1001,7 +1080,7 @@ TEST_F(IceConnectTest, TestConnectTrickleOneStreamOneComponent) {
|
|||
AddStream("first", 1);
|
||||
ASSERT_TRUE(Gather(true));
|
||||
ConnectTrickle();
|
||||
DoTrickle(0);
|
||||
SimulateTrickle(0);
|
||||
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
|
||||
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
|
||||
}
|
||||
|
@ -1011,12 +1090,21 @@ TEST_F(IceConnectTest, TestConnectTrickleTwoStreamsOneComponent) {
|
|||
AddStream("second", 1);
|
||||
ASSERT_TRUE(Gather(true));
|
||||
ConnectTrickle();
|
||||
DoTrickle(0);
|
||||
DoTrickle(1);
|
||||
SimulateTrickle(0);
|
||||
SimulateTrickle(1);
|
||||
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
|
||||
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestConnectRealTrickleOneStreamOneComponent) {
|
||||
AddStream("first", 1);
|
||||
AddStream("second", 1);
|
||||
ASSERT_TRUE(Gather(false));
|
||||
ConnectTrickle(TRICKLE_REAL);
|
||||
ASSERT_TRUE_WAIT(p1_->ice_complete(), 5000);
|
||||
ASSERT_TRUE_WAIT(p2_->ice_complete(), 5000);
|
||||
WaitForGather(); // ICE can complete before we finish gathering.
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestSendReceive) {
|
||||
AddStream("first", 1);
|
||||
|
@ -1195,6 +1283,15 @@ int main(int argc, char **argv)
|
|||
g_turn_server="";
|
||||
}
|
||||
|
||||
std::string tmp = get_environment("STUN_SERVER_ADDRESS");
|
||||
if (tmp != "")
|
||||
g_stun_server_address = tmp;
|
||||
|
||||
|
||||
tmp = get_environment("STUN_SERVER_HOSTNAME");
|
||||
if (tmp != "")
|
||||
g_stun_server_hostname = tmp;
|
||||
|
||||
test_utils = new MtransportTestUtils();
|
||||
NSS_NoDB_Init(nullptr);
|
||||
NSS_SetDomesticPolicy();
|
||||
|
|
|
@ -416,8 +416,8 @@ static void nr_ice_candidate_fire_ready_cb(NR_SOCKET s, int how, void *cb_arg)
|
|||
{
|
||||
nr_ice_candidate *cand = cb_arg;
|
||||
|
||||
cand->ready_cb(0, 0, cand->ready_cb_arg);
|
||||
cand->ready_cb_timer = 0;
|
||||
cand->ready_cb(0, 0, cand->ready_cb_arg);
|
||||
}
|
||||
|
||||
int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg)
|
||||
|
|
|
@ -249,7 +249,7 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
|
|||
ABORT(r);
|
||||
cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
|
||||
cand->done_cb=nr_ice_initialize_finished_cb;
|
||||
cand->cb_arg=ctx;
|
||||
cand->cb_arg=cand;
|
||||
|
||||
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
|
||||
component->candidate_ct++;
|
||||
|
@ -315,7 +315,7 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
|
|||
cand=TAILQ_FIRST(&component->candidates);
|
||||
while(cand){
|
||||
if(cand->state!=NR_ICE_CAND_STATE_INITIALIZING){
|
||||
if(r=nr_ice_candidate_initialize(cand,nr_ice_initialize_finished_cb,ctx)){
|
||||
if(r=nr_ice_candidate_initialize(cand,nr_ice_initialize_finished_cb,cand)){
|
||||
if(r!=R_WOULDBLOCK){
|
||||
ctx->uninitialized_candidates--;
|
||||
cand->state=NR_ICE_CAND_STATE_FAILED;
|
||||
|
@ -330,74 +330,64 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
|
|||
return(_status);
|
||||
}
|
||||
|
||||
/* Prune redundant candidates. We use an n^2 algorithm for now.
|
||||
/*
|
||||
Compare this newly initialized candidate against the other initialized
|
||||
candidates and discard the lower-priority one if they are redundant.
|
||||
|
||||
This algorithm combined with the other algorithms, favors
|
||||
host > srflx > relay
|
||||
|
||||
This actually won't prune relayed in the very rare
|
||||
case that relayed is the same. Not relevant in practice.
|
||||
*/
|
||||
|
||||
int nr_ice_component_prune_candidates(nr_ice_ctx *ctx, nr_ice_component *comp)
|
||||
*/
|
||||
int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned)
|
||||
{
|
||||
nr_ice_candidate *c1,*c1n,*c2;
|
||||
nr_ice_candidate *c2, *tmp = NULL;
|
||||
|
||||
c1=TAILQ_FIRST(&comp->candidates);
|
||||
while(c1){
|
||||
c1n=TAILQ_NEXT(c1,entry_comp);
|
||||
if(c1->state!=NR_ICE_CAND_STATE_INITIALIZED){
|
||||
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Removing non-initialized candidate %s",
|
||||
ctx->label,c1->label);
|
||||
if (c1->state == NR_ICE_CAND_STATE_INITIALIZING) {
|
||||
r_log(LOG_ICE,LOG_NOTICE, "ICE(%s): Removing candidate %s which is in INITIALIZING state",
|
||||
ctx->label, c1->label);
|
||||
}
|
||||
TAILQ_REMOVE(&comp->candidates,c1,entry_comp);
|
||||
comp->candidate_ct--;
|
||||
TAILQ_REMOVE(&c1->isock->candidates,c1,entry_sock);
|
||||
/* schedule this delete for later as we don't want to delete the underlying
|
||||
* objects while in the middle of a callback on one of those objects */
|
||||
NR_ASYNC_SCHEDULE(nr_ice_candidate_destroy_cb,c1);
|
||||
goto next_c1;
|
||||
}
|
||||
*was_pruned = 0;
|
||||
c2 = TAILQ_FIRST(&comp->candidates);
|
||||
while(c2){
|
||||
if((c1 != c2) &&
|
||||
(c2->state == NR_ICE_CAND_STATE_INITIALIZED) &&
|
||||
!nr_transport_addr_cmp(&c1->base,&c2->base,NR_TRANSPORT_ADDR_CMP_MODE_ALL) &&
|
||||
!nr_transport_addr_cmp(&c1->addr,&c2->addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
|
||||
|
||||
c2=TAILQ_NEXT(c1,entry_comp);
|
||||
if((c1->type == c2->type) ||
|
||||
(c1->type==HOST && c2->type == SERVER_REFLEXIVE) ||
|
||||
(c2->type==HOST && c1->type == SERVER_REFLEXIVE)){
|
||||
|
||||
while(c2){
|
||||
nr_ice_candidate *tmp;
|
||||
/*
|
||||
These are redundant. Remove the lower pri one.
|
||||
|
||||
if(!nr_transport_addr_cmp(&c1->base,&c2->base,NR_TRANSPORT_ADDR_CMP_MODE_ALL) && !nr_transport_addr_cmp(&c1->addr,&c2->addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
|
||||
|
||||
if((c1->type == c2->type) ||
|
||||
(c1->type==HOST && c2->type == SERVER_REFLEXIVE) ||
|
||||
(c2->type==HOST && c1->type == SERVER_REFLEXIVE)){
|
||||
|
||||
/* OK these are redundant. Remove the lower pri one */
|
||||
tmp=c2;
|
||||
c2=TAILQ_NEXT(c2,entry_comp);
|
||||
if(c1n==tmp)
|
||||
c1n=c2;
|
||||
|
||||
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Removing redundant candidate %s",
|
||||
ctx->label,tmp->label);
|
||||
|
||||
TAILQ_REMOVE(&comp->candidates,tmp,entry_comp);
|
||||
comp->candidate_ct--;
|
||||
TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock);
|
||||
|
||||
nr_ice_candidate_destroy(&tmp);
|
||||
Since this algorithmis run whenever a new candidate
|
||||
is initialized, there should at most one duplicate.
|
||||
*/
|
||||
if (c1->priority < c2->priority) {
|
||||
tmp = c1;
|
||||
*was_pruned = 1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
c2=TAILQ_NEXT(c2,entry_comp);
|
||||
else {
|
||||
tmp = c2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
next_c1:
|
||||
c1=c1n;
|
||||
|
||||
c2=TAILQ_NEXT(c2,entry_comp);
|
||||
}
|
||||
|
||||
return(0);
|
||||
if (tmp) {
|
||||
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Removing redundant candidate %s",
|
||||
ctx->label,tmp->label);
|
||||
|
||||
TAILQ_REMOVE(&comp->candidates,tmp,entry_comp);
|
||||
comp->candidate_ct--;
|
||||
TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock);
|
||||
|
||||
nr_ice_candidate_destroy(&tmp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Section 7.2.1 */
|
||||
|
@ -652,74 +642,85 @@ int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_c
|
|||
return(_status);
|
||||
}
|
||||
|
||||
int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp)
|
||||
int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote)
|
||||
{
|
||||
nr_ice_candidate *lcand,*pcand;
|
||||
int r, _status;
|
||||
nr_ice_candidate *pcand;
|
||||
nr_ice_cand_pair *pair=0;
|
||||
nr_ice_socket *isock;
|
||||
int r,_status;
|
||||
char codeword[5];
|
||||
|
||||
nr_ice_compute_codeword(lcand->label,strlen(lcand->label),codeword);
|
||||
r_log(LOG_ICE,LOG_DEBUG,"Pairing local candidate %s:%s",codeword,lcand->label);
|
||||
|
||||
switch(lcand->type){
|
||||
case HOST:
|
||||
break;
|
||||
case SERVER_REFLEXIVE:
|
||||
case PEER_REFLEXIVE:
|
||||
/* Don't actually pair these candidates */
|
||||
goto done;
|
||||
break;
|
||||
case RELAYED:
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
ABORT(R_INTERNAL);
|
||||
break;
|
||||
}
|
||||
|
||||
pcand=TAILQ_FIRST(&pcomp->candidates);
|
||||
while(pcand){
|
||||
/*
|
||||
Two modes, depending on |pair_all_remote|
|
||||
|
||||
1. Pair remote candidates which have not been paired
|
||||
(used in initial pairing or in processing the other side's
|
||||
trickle candidates).
|
||||
2. Pair any remote candidate (used when processing our own
|
||||
trickle candidates).
|
||||
*/
|
||||
if (pair_all_remote || (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED)) {
|
||||
/* If we are pairing our own trickle candidates, the remote candidate should
|
||||
all be paired */
|
||||
if (pair_all_remote)
|
||||
assert (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_PAIRED);
|
||||
|
||||
nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
|
||||
r_log(LOG_ICE,LOG_DEBUG,"Pairing with peer candidate %s:%s",codeword,pcand->label);
|
||||
|
||||
if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
|
||||
ABORT(r);
|
||||
|
||||
if(r=nr_ice_candidate_pair_insert(&pcomp->stream->check_list,
|
||||
pair))
|
||||
ABORT(r);
|
||||
}
|
||||
|
||||
pcand=TAILQ_NEXT(pcand,entry_comp);
|
||||
}
|
||||
|
||||
done:
|
||||
_status = 0;
|
||||
abort:
|
||||
return(_status);
|
||||
}
|
||||
|
||||
int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp)
|
||||
{
|
||||
nr_ice_candidate *lcand, *pcand;
|
||||
nr_ice_socket *isock;
|
||||
int r,_status;
|
||||
|
||||
r_log(LOG_ICE,LOG_DEBUG,"Pairing candidates======");
|
||||
|
||||
/* Create the candidate pairs */
|
||||
lcand=TAILQ_FIRST(&lcomp->candidates);
|
||||
while(lcand){
|
||||
int was_paired = 0;
|
||||
|
||||
nr_ice_compute_codeword(lcand->label,strlen(lcand->label),codeword);
|
||||
r_log(LOG_ICE,LOG_DEBUG,"Examining local candidate %s:%s",codeword,lcand->label);
|
||||
|
||||
switch(lcand->type){
|
||||
case HOST:
|
||||
break;
|
||||
case SERVER_REFLEXIVE:
|
||||
case PEER_REFLEXIVE:
|
||||
/* Don't actually pair these candidates */
|
||||
goto next_cand;
|
||||
break;
|
||||
case RELAYED:
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
ABORT(R_INTERNAL);
|
||||
break;
|
||||
if (lcand->state == NR_ICE_CAND_STATE_INITIALIZED) {
|
||||
if ((r = nr_ice_component_pair_candidate(pctx, pcomp, lcand, 0)))
|
||||
ABORT(r);
|
||||
}
|
||||
|
||||
/* PAIR with each peer*/
|
||||
if(TAILQ_EMPTY(&pcomp->candidates)) {
|
||||
/* can happen if our peer proposes no (or all bogus) candidates */
|
||||
goto next_cand;
|
||||
}
|
||||
pcand=TAILQ_FIRST(&pcomp->candidates);
|
||||
while(pcand){
|
||||
/* Only pair peer candidates which have not yet been paired.
|
||||
This allows "trickle ICE". (Not yet standardized, but
|
||||
part of WebRTC).
|
||||
|
||||
TODO(ekr@rtfm.com): Add refernece to the spec when there
|
||||
is one.
|
||||
*/
|
||||
if (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED) {
|
||||
nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
|
||||
r_log(LOG_ICE,LOG_DEBUG,"Examining peer candidate %s:%s",codeword,pcand->label);
|
||||
|
||||
if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
|
||||
ABORT(r);
|
||||
|
||||
if(r=nr_ice_candidate_pair_insert(&pcomp->stream->check_list,
|
||||
pair))
|
||||
ABORT(r);
|
||||
}
|
||||
else {
|
||||
was_paired = 1;
|
||||
}
|
||||
pcand=TAILQ_NEXT(pcand,entry_comp);
|
||||
}
|
||||
|
||||
if(!pair)
|
||||
goto next_cand;
|
||||
|
||||
next_cand:
|
||||
lcand=TAILQ_NEXT(lcand,entry_comp);
|
||||
}
|
||||
|
||||
|
|
|
@ -82,8 +82,9 @@ 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);
|
||||
int nr_ice_component_prune_candidates(nr_ice_ctx *ctx, nr_ice_component *comp);
|
||||
int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp);
|
||||
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);
|
||||
|
|
|
@ -64,6 +64,7 @@ static int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out);
|
|||
static int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out);
|
||||
#endif /* USE_TURN */
|
||||
static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg);
|
||||
static int nr_ice_ctx_pair_new_trickle_candidates(nr_ice_ctx *ctx, nr_ice_candidate *cand);
|
||||
|
||||
int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out)
|
||||
{
|
||||
|
@ -441,13 +442,38 @@ int nr_ice_ctx_destroy(nr_ice_ctx **ctxp)
|
|||
|
||||
void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg)
|
||||
{
|
||||
nr_ice_ctx *ctx=cb_arg;
|
||||
int r,_status;
|
||||
nr_ice_candidate *cand=cb_arg;
|
||||
nr_ice_ctx *ctx;
|
||||
|
||||
|
||||
assert(cb_arg);
|
||||
if (!cb_arg)
|
||||
return;
|
||||
ctx = cand->ctx;
|
||||
|
||||
/* r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Candidate %s %s",ctx->label,
|
||||
cand->label, cand->state==NR_ICE_CAND_STATE_INITIALIZED?"INITIALIZED":"FAILED");
|
||||
*/
|
||||
ctx->uninitialized_candidates--;
|
||||
|
||||
if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) {
|
||||
int was_pruned = 0;
|
||||
|
||||
if (r=nr_ice_component_maybe_prune_candidate(ctx, cand->component,
|
||||
cand, &was_pruned)) {
|
||||
r_log(LOG_ICE, LOG_NOTICE, "ICE(%s): Problem pruning candidates",ctx->label);
|
||||
}
|
||||
|
||||
/* If we are initialized, the candidate wasn't pruned,
|
||||
and we have a trickle ICE callback fire the callback */
|
||||
if (ctx->trickle_cb && !was_pruned) {
|
||||
ctx->trickle_cb(ctx->trickle_cb_arg, ctx, cand->stream, cand->component_id, cand);
|
||||
|
||||
if (r==nr_ice_ctx_pair_new_trickle_candidates(ctx, cand)) {
|
||||
r_log(LOG_ICE,LOG_ERR, "ICE(%s): All could not pair new trickle candidate",ctx->label);
|
||||
/* But continue */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ctx->uninitialized_candidates==0){
|
||||
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): All candidates initialized",ctx->label);
|
||||
ctx->state=NR_ICE_STATE_INITIALIZED;
|
||||
|
@ -463,6 +489,28 @@ void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg)
|
|||
}
|
||||
}
|
||||
|
||||
static int nr_ice_ctx_pair_new_trickle_candidates(nr_ice_ctx *ctx, nr_ice_candidate *cand)
|
||||
{
|
||||
int r,_status;
|
||||
nr_ice_peer_ctx *pctx;
|
||||
|
||||
pctx=STAILQ_FIRST(&ctx->peers);
|
||||
while(pctx){
|
||||
if (pctx->state == NR_ICE_PEER_STATE_PAIRED) {
|
||||
r = nr_ice_peer_ctx_pair_new_trickle_candidate(ctx, pctx, cand);
|
||||
if (r)
|
||||
ABORT(r);
|
||||
}
|
||||
|
||||
pctx=STAILQ_NEXT(pctx,entry);
|
||||
}
|
||||
|
||||
_status=0;
|
||||
abort:
|
||||
return(_status);
|
||||
}
|
||||
|
||||
|
||||
#define MAXADDRS 100 // Ridiculously high
|
||||
int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg)
|
||||
{
|
||||
|
@ -689,3 +737,11 @@ int nr_ice_ctx_finalize(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx)
|
|||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int nr_ice_ctx_set_trickle_cb(nr_ice_ctx *ctx, nr_ice_trickle_candidate_cb cb, void *cb_arg)
|
||||
{
|
||||
ctx->trickle_cb = cb;
|
||||
ctx->trickle_cb_arg = cb_arg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -89,6 +89,9 @@ typedef struct nr_ice_ctx_ nr_ice_ctx;
|
|||
typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx;
|
||||
typedef struct nr_ice_candidate_ nr_ice_candidate;
|
||||
typedef struct nr_ice_cand_pair_ nr_ice_cand_pair;
|
||||
typedef void (*nr_ice_trickle_candidate_cb) (void *cb_arg,
|
||||
nr_ice_ctx *ctx, nr_ice_media_stream *stream, int component_id,
|
||||
nr_ice_candidate *candidate);
|
||||
|
||||
#include "ice_socket.h"
|
||||
#include "ice_component.h"
|
||||
|
@ -144,6 +147,9 @@ struct nr_ice_ctx_ {
|
|||
|
||||
NR_async_cb done_cb;
|
||||
void *cb_arg;
|
||||
|
||||
nr_ice_trickle_candidate_cb trickle_cb;
|
||||
void *trickle_cb_arg;
|
||||
};
|
||||
|
||||
int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp);
|
||||
|
@ -166,6 +172,9 @@ int nr_ice_ctx_set_stun_servers(nr_ice_ctx *ctx,nr_ice_stun_server *servers, int
|
|||
int nr_ice_ctx_set_turn_servers(nr_ice_ctx *ctx,nr_ice_turn_server *servers, int ct);
|
||||
int nr_ice_ctx_set_resolver(nr_ice_ctx *ctx, nr_resolver *resolver);
|
||||
int nr_ice_ctx_set_interface_prioritizer(nr_ice_ctx *ctx, nr_interface_prioritizer *prioritizer);
|
||||
int nr_ice_ctx_set_trickle_cb(nr_ice_ctx *ctx, nr_ice_trickle_candidate_cb cb, void *cb_arg);
|
||||
|
||||
#define NR_ICE_MAX_ATTRIBUTE_SIZE 256
|
||||
|
||||
extern int LOG_ICE;
|
||||
|
||||
|
|
|
@ -140,14 +140,13 @@ int nr_ice_media_stream_initialize(nr_ice_ctx *ctx, nr_ice_media_stream *stream)
|
|||
return(_status);
|
||||
}
|
||||
|
||||
#define MAX_ATTRIBUTE_SIZE 256
|
||||
|
||||
int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attrsp, int *attrctp)
|
||||
{
|
||||
int attrct=0;
|
||||
nr_ice_component *comp;
|
||||
char **attrs=0;
|
||||
int index=0;
|
||||
nr_ice_candidate *cand;
|
||||
int r,_status;
|
||||
|
||||
*attrctp=0;
|
||||
|
@ -156,12 +155,15 @@ int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attr
|
|||
comp=STAILQ_FIRST(&stream->components);
|
||||
while(comp){
|
||||
if (comp->state != NR_ICE_COMPONENT_DISABLED) {
|
||||
if(r=nr_ice_component_prune_candidates(stream->ctx,comp))
|
||||
ABORT(r);
|
||||
cand = TAILQ_FIRST(&comp->candidates);
|
||||
while(cand){
|
||||
if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) {
|
||||
++attrct;
|
||||
}
|
||||
|
||||
attrct+=comp->candidate_ct;
|
||||
cand = TAILQ_NEXT(cand, entry_comp);
|
||||
}
|
||||
}
|
||||
|
||||
comp=STAILQ_NEXT(comp,entry);
|
||||
}
|
||||
|
||||
|
@ -174,7 +176,7 @@ int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attr
|
|||
if(!(attrs=RCALLOC(sizeof(char *)*attrct)))
|
||||
ABORT(R_NO_MEMORY);
|
||||
for(index=0;index<attrct;index++){
|
||||
if(!(attrs[index]=RMALLOC(MAX_ATTRIBUTE_SIZE)))
|
||||
if(!(attrs[index]=RMALLOC(NR_ICE_MAX_ATTRIBUTE_SIZE)))
|
||||
ABORT(R_NO_MEMORY);
|
||||
}
|
||||
|
||||
|
@ -187,12 +189,15 @@ int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attr
|
|||
|
||||
cand=TAILQ_FIRST(&comp->candidates);
|
||||
while(cand){
|
||||
assert(index < attrct);
|
||||
if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) {
|
||||
assert(index < attrct);
|
||||
|
||||
if(r=nr_ice_format_candidate_attribute(cand, attrs[index],MAX_ATTRIBUTE_SIZE))
|
||||
ABORT(r);
|
||||
|
||||
index++;
|
||||
if(r=nr_ice_format_candidate_attribute(cand, attrs[index],NR_ICE_MAX_ATTRIBUTE_SIZE))
|
||||
ABORT(r);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
cand=TAILQ_NEXT(cand,entry_comp);
|
||||
}
|
||||
|
@ -243,15 +248,17 @@ int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int c
|
|||
*/
|
||||
cand=TAILQ_FIRST(&comp->candidates);
|
||||
while(cand){
|
||||
if (!best_cand) {
|
||||
best_cand = cand;
|
||||
}
|
||||
else {
|
||||
if (best_cand->type < cand->type) {
|
||||
if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) {
|
||||
if (!best_cand) {
|
||||
best_cand = cand;
|
||||
} else if (best_cand->type == cand->type) {
|
||||
if (best_cand->priority < cand->priority)
|
||||
}
|
||||
else {
|
||||
if (best_cand->type < cand->type) {
|
||||
best_cand = cand;
|
||||
} else if (best_cand->type == cand->type) {
|
||||
if (best_cand->priority < cand->priority)
|
||||
best_cand = cand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -811,6 +818,21 @@ int nr_ice_media_stream_finalize(nr_ice_media_stream *lstr,nr_ice_media_stream *
|
|||
return(0);
|
||||
}
|
||||
|
||||
int nr_ice_media_stream_pair_new_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, nr_ice_candidate *cand)
|
||||
{
|
||||
int r,_status;
|
||||
nr_ice_component *comp;
|
||||
|
||||
if ((r=nr_ice_media_stream_find_component(pstream, cand->component_id, &comp)))
|
||||
ABORT(R_NOT_FOUND);
|
||||
|
||||
if (r=nr_ice_component_pair_candidate(pctx, comp, cand, 1))
|
||||
ABORT(r);
|
||||
|
||||
_status=0;
|
||||
abort:
|
||||
return(_status);
|
||||
}
|
||||
|
||||
int nr_ice_media_stream_disable_component(nr_ice_media_stream *stream, int component_id)
|
||||
{
|
||||
|
|
|
@ -95,7 +95,7 @@ int nr_ice_media_stream_addrs(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, i
|
|||
int
|
||||
nr_ice_peer_ctx_parse_media_stream_attribute(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *attr);
|
||||
int nr_ice_media_stream_disable_component(nr_ice_media_stream *stream, int component_id);
|
||||
|
||||
int nr_ice_media_stream_pair_new_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, nr_ice_candidate *cand);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -56,6 +56,8 @@ int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label,
|
|||
if(!(pctx=RCALLOC(sizeof(nr_ice_peer_ctx))))
|
||||
ABORT(R_NO_MEMORY);
|
||||
|
||||
pctx->state = NR_ICE_PEER_STATE_UNPAIRED;
|
||||
|
||||
if(!(pctx->label=r_strdup(label)))
|
||||
ABORT(R_NO_MEMORY);
|
||||
|
||||
|
@ -257,25 +259,14 @@ int nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str
|
|||
|
||||
int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate)
|
||||
{
|
||||
/* First need to find the stream. Because we don't have forward pointers,
|
||||
iterate through all the peer streams to find one that matches us */
|
||||
nr_ice_media_stream *pstream;
|
||||
int r,_status;
|
||||
int needs_pairing = 0;
|
||||
|
||||
r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) parsing trickle ICE candidate %s",pctx->ctx->label,pctx->label,candidate);
|
||||
|
||||
pstream=STAILQ_FIRST(&pctx->peer_streams);
|
||||
while(pstream) {
|
||||
if (pstream->local_stream == stream)
|
||||
break;
|
||||
|
||||
pstream = STAILQ_NEXT(pstream, entry);
|
||||
}
|
||||
if (!pstream) {
|
||||
r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label);
|
||||
ABORT(R_NOT_FOUND);
|
||||
}
|
||||
r = nr_ice_peer_ctx_find_pstream(pctx, stream, &pstream);
|
||||
if (r)
|
||||
ABORT(r);
|
||||
|
||||
switch(pstream->ice_state) {
|
||||
case NR_ICE_MEDIA_STREAM_UNPAIRED:
|
||||
|
@ -354,17 +345,36 @@ int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
|
|||
stream=STAILQ_NEXT(stream,entry);
|
||||
}
|
||||
|
||||
pctx->state = NR_ICE_PEER_STATE_PAIRED;
|
||||
|
||||
_status=0;
|
||||
abort:
|
||||
return(_status);
|
||||
}
|
||||
|
||||
|
||||
int nr_ice_peer_ctx_pair_new_trickle_candidate(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx, nr_ice_candidate *cand)
|
||||
{
|
||||
int r, _status;
|
||||
nr_ice_media_stream *pstream;
|
||||
|
||||
r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) pairing local trickle ICE candidate %s",pctx->ctx->label,pctx->label,cand->label);
|
||||
if ((r = nr_ice_peer_ctx_find_pstream(pctx, cand->stream, &pstream)))
|
||||
ABORT(r);
|
||||
|
||||
if ((r = nr_ice_media_stream_pair_new_trickle_candidate(pctx, pstream, cand)))
|
||||
ABORT(r);
|
||||
|
||||
_status=0;
|
||||
abort:
|
||||
return _status;
|
||||
}
|
||||
|
||||
int nr_ice_peer_ctx_disable_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *lstream, int component_id)
|
||||
{
|
||||
int r, _status;
|
||||
nr_ice_media_stream *pstream;
|
||||
nr_ice_component *component;
|
||||
int j;
|
||||
|
||||
if ((r=nr_ice_peer_ctx_find_pstream(pctx, lstream, &pstream)))
|
||||
ABORT(r);
|
||||
|
@ -543,7 +553,6 @@ static void nr_ice_peer_ctx_fire_done(NR_SOCKET s, int how, void *cb_arg)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* OK, a stream just went ready. Examine all the streams to see if we're
|
||||
maybe miraculously done */
|
||||
int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
|
||||
|
|
|
@ -40,6 +40,10 @@ extern "C" {
|
|||
#endif /* __cplusplus */
|
||||
|
||||
struct nr_ice_peer_ctx_ {
|
||||
int state;
|
||||
#define NR_ICE_PEER_STATE_UNPAIRED 1
|
||||
#define NR_ICE_PEER_STATE_PAIRED 2
|
||||
|
||||
char *label;
|
||||
nr_ice_ctx *ctx;
|
||||
nr_ice_handler *handler;
|
||||
|
@ -80,6 +84,7 @@ int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stre
|
|||
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);
|
||||
int nr_ice_peer_ctx_pair_new_trickle_candidate(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx, nr_ice_candidate *cand);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче