Bug 842549 - Part 1. Generate trickle candidates from nICEr, with testing r=abr

This commit is contained in:
EKR 2013-09-19 09:17:52 -07:00
parent 158158f87e
commit 05efd23c6a
14 changed files with 499 additions and 273 deletions

View File

@ -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);
}

View File

@ -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
};

View File

@ -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;
}

View File

@ -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_;
};

View File

@ -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();

View File

@ -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)

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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
}

View File

@ -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)

View File

@ -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
}