--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -70,16 +70,17 @@ extern "C" {
#include "r_memory.h"
#include "ice_reg.h"
#include "ice_util.h"
#include "transport_addr.h"
#include "nr_crypto.h"
#include "nr_socket.h"
#include "nr_socket_local.h"
#include "stun_client_ctx.h"
+#include "stun_reg.h"
#include "stun_server_ctx.h"
#include "ice_codeword.h"
#include "ice_ctx.h"
#include "ice_candidate.h"
#include "ice_handler.h"
}
// Local includes
@@ -380,17 +381,18 @@ void NrIceCtx::trickle_cb(void *arg, nr_
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,
- bool set_interface_priorities) {
+ bool set_interface_priorities,
+ bool allow_loopback) {
RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer);
// Initialize the crypto callbacks and logging stuff
if (!initialized) {
NR_reg_init(NR_REG_MODE_LOCAL);
RLogRingBuffer::CreateInstance();
nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
@@ -428,16 +430,20 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const
NR_reg_set_uchar((char *)"ice.pref.interface.vmnet7", 235);
NR_reg_set_uchar((char *)"ice.pref.interface.vmnet8", 234);
NR_reg_set_uchar((char *)"ice.pref.interface.virbr0", 233);
NR_reg_set_uchar((char *)"ice.pref.interface.wlan0", 232);
}
NR_reg_set_uint4((char *)"stun.client.maximum_transmits",7);
NR_reg_set_uint4((char *)NR_ICE_REG_TRICKLE_GRACE_PERIOD, 5000);
+
+ if (allow_loopback) {
+ NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
+ }
}
// Create the ICE context
int r;
UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER:
NR_ICE_CTX_FLAGS_ANSWERER;
flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
@@ -499,16 +505,25 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const
ctx->sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
if (!NS_SUCCEEDED(rv))
return nullptr;
return ctx;
}
+// ONLY USE THIS FOR TESTING. Will cause totally unpredictable and possibly very
+// bad effects if ICE is still live.
+void NrIceCtx::internal_DeinitializeGlobal() {
+ NR_reg_del((char *)"stun");
+ NR_reg_del((char *)"ice");
+ RLogRingBuffer::DestroyInstance();
+ nr_crypto_vtbl = nullptr;
+ initialized = false;
+}
NrIceCtx::~NrIceCtx() {
MOZ_MTLOG(ML_DEBUG, "Destroying ICE ctx '" << name_ <<"'");
nr_ice_peer_ctx_destroy(&peer_);
nr_ice_ctx_destroy(&ctx_);
delete ice_handler_vtbl_;
delete ice_handler_;
}
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -185,17 +185,23 @@ class NrIceCtx {
};
enum Controlling { ICE_CONTROLLING,
ICE_CONTROLLED
};
static RefPtr<NrIceCtx> Create(const std::string& name,
bool offerer,
- bool set_interface_priorities = true);
+ bool set_interface_priorities = true,
+ bool allow_loopback = false);
+
+ // Deinitialize all ICE global state. Used only for testing.
+ static void internal_DeinitializeGlobal();
+
+
nr_ice_ctx *ctx() { return ctx_; }
nr_ice_peer_ctx *peer() { return peer_; }
// Testing only.
void destroy_peer_ctx();
// Create a media stream
RefPtr<NrIceMediaStream> CreateStream(const std::string& name,
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -82,16 +82,23 @@ typedef std::string (*CandidateFilter)(c
static std::string IsRelayCandidate(const std::string& candidate) {
if (candidate.find("typ relay") != std::string::npos) {
return candidate;
}
return std::string();
}
+static std::string IsLoopbackCandidate(const std::string& candidate) {
+ if (candidate.find("127.0.0.") != std::string::npos) {
+ return candidate;
+ }
+ return std::string();
+}
+
static std::string SabotageHostCandidateAndDropReflexive(
const std::string& candidate) {
if (candidate.find("typ srflx") != std::string::npos) {
return std::string();
}
if (candidate.find("typ host") != std::string::npos) {
return kUnreachableHostIceCandidate;
@@ -213,19 +220,20 @@ class SchedulableTrickleCandidate {
void *timer_handle_;
DISALLOW_COPY_ASSIGN(SchedulableTrickleCandidate);
};
class IceTestPeer : public sigslot::has_slots<> {
public:
- IceTestPeer(const std::string& name, bool offerer, bool set_priorities) :
+ IceTestPeer(const std::string& name, bool offerer, bool set_priorities,
+ bool allow_loopback = false) :
name_(name),
- ice_ctx_(NrIceCtx::Create(name, offerer, set_priorities)),
+ ice_ctx_(NrIceCtx::Create(name, offerer, set_priorities, allow_loopback)),
streams_(),
candidates_(),
gathering_complete_(false),
ready_ct_(0),
ice_complete_(false),
ice_reached_checking_(false),
received_(0),
sent_(0),
@@ -269,16 +277,17 @@ class IceTestPeer : public sigslot::has_
streams_.push_back(stream);
stream->SignalCandidate.connect(this, &IceTestPeer::CandidateInitialized);
stream->SignalReady.connect(this, &IceTestPeer::StreamReady);
stream->SignalFailed.connect(this, &IceTestPeer::StreamFailed);
stream->SignalPacketReceived.connect(this, &IceTestPeer::PacketReceived);
}
void SetStunServer(const std::string addr, uint16_t port) {
+
std::vector<NrIceStunServer> stun_servers;
ScopedDeletePtr<NrIceStunServer> server(NrIceStunServer::Create(addr,
port));
stun_servers.push_back(*server);
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
}
void SetTurnServer(const std::string addr, uint16_t port,
@@ -383,16 +392,21 @@ class IceTestPeer : public sigslot::has_
void SetExpectedTypes(NrIceCandidate::Type local,
NrIceCandidate::Type remote,
std::string local_transport = kNrIceTransportUdp) {
expected_local_type_ = local;
expected_local_transport_ = local_transport;
expected_remote_type_ = remote;
}
+ void SetExpectedCandidateAddr(const std::string& addr) {
+ expected_local_addr_ = addr;
+ expected_remote_addr_ = addr;
+ }
+
bool gathering_complete() { return gathering_complete_; }
int ready_ct() { return ready_ct_; }
bool is_ready(size_t stream) {
return streams_[stream]->state() == NrIceMediaStream::ICE_OPEN;
}
bool ice_complete() { return ice_complete_; }
bool ice_reached_checking() { return ice_reached_checking_; }
size_t received() { return received_; }
@@ -479,16 +493,27 @@ class IceTestPeer : public sigslot::has_
nsresult TrickleCandidate_s(const std::string &candidate, size_t stream) {
return streams_[stream]->ParseTrickleCandidate(candidate);
}
void DumpCandidate(std::string which, const NrIceCandidate& cand) {
std::string type;
+ std::string addr;
+ int port;
+
+ if (which.find("Remote") != std::string::npos) {
+ addr = cand.cand_addr.host;
+ port = cand.cand_addr.port;
+ }
+ else {
+ addr = cand.local_addr.host;
+ port = cand.local_addr.port;
+ }
switch(cand.type) {
case NrIceCandidate::ICE_HOST:
type = "host";
break;
case NrIceCandidate::ICE_SERVER_REFLEXIVE:
type = "srflx";
break;
case NrIceCandidate::ICE_PEER_REFLEXIVE:
@@ -499,23 +524,24 @@ class IceTestPeer : public sigslot::has_
if (which.find("Local") != std::string::npos) {
type += "(" + cand.local_addr.transport + ")";
}
break;
default:
FAIL();
};
+
std::cerr << which
<< " --> "
<< type
<< " "
- << cand.local_addr.host
+ << addr
<< ":"
- << cand.local_addr.port
+ << port
<< " codeword="
<< cand.codeword
<< std::endl;
}
void DumpAndCheckActiveCandidates_s() {
std::cerr << "Active candidates:" << std::endl;
for (size_t i=0; i < streams_.size(); ++i) {
@@ -530,16 +556,22 @@ class IceTestPeer : public sigslot::has_
std::cerr << "Component unpaired or disabled." << std::endl;
} else {
ASSERT_TRUE(NS_SUCCEEDED(res));
DumpCandidate("Local ", *local);
ASSERT_EQ(expected_local_type_, local->type);
ASSERT_EQ(expected_local_transport_, local->local_addr.transport);
DumpCandidate("Remote ", *remote);
ASSERT_EQ(expected_remote_type_, remote->type);
+ if (!expected_local_addr_.empty()) {
+ ASSERT_EQ(expected_local_addr_, local->cand_addr.host);
+ }
+ if (!expected_remote_addr_.empty()) {
+ ASSERT_EQ(expected_remote_addr_, remote->cand_addr.host);
+ }
delete local;
delete remote;
}
}
}
}
void DumpAndCheckActiveCandidates() {
@@ -856,16 +888,18 @@ class IceTestPeer : public sigslot::has_
size_t sent_;
NrIceResolverFake fake_resolver_;
nsRefPtr<NrIceResolver> dns_resolver_;
IceTestPeer *remote_;
CandidateFilter candidate_filter_;
NrIceCandidate::Type expected_local_type_;
std::string expected_local_transport_;
NrIceCandidate::Type expected_remote_type_;
+ std::string expected_local_addr_;
+ std::string expected_remote_addr_;
TrickleMode trickle_mode_;
int trickled_;
bool simulate_ice_lite_;
};
void SchedulableTrickleCandidate::Trickle() {
timer_handle_ = nullptr;
nsresult res = peer_->TrickleCandidate_s(candidate_, stream_);
@@ -873,34 +907,53 @@ void SchedulableTrickleCandidate::Trickl
}
class IceGatherTest : public ::testing::Test {
public:
void SetUp() {
test_utils->sts_target()->Dispatch(WrapRunnable(TestStunServer::GetInstance(),
&TestStunServer::Reset),
NS_DISPATCH_SYNC);
- peer_ = new IceTestPeer("P1", true, false);
- peer_->AddStream(1);
+ }
+
+ void TearDown() {
+ peer_ = nullptr;
+
+ test_utils->sts_target()->Dispatch(WrapRunnable(this,
+ &IceGatherTest::TearDown_s),
+ NS_DISPATCH_SYNC);
+ }
+
+ void TearDown_s() {
+ NrIceCtx::internal_DeinitializeGlobal();
+ }
+
+ void EnsurePeer() {
+ if (!peer_) {
+ peer_ = new IceTestPeer("P1", true, false);
+ peer_->AddStream(1);
+ }
}
void Gather(unsigned int waitTime = kDefaultTimeout) {
- peer_->Gather();
+ EnsurePeer();
+ peer_->Gather();
if (waitTime) {
WaitForGather(waitTime);
}
}
void WaitForGather(unsigned int waitTime = kDefaultTimeout) {
ASSERT_TRUE_WAIT(peer_->gathering_complete(), waitTime);
}
void UseFakeStunServerWithResponse(const std::string& fake_addr,
uint16_t fake_port) {
+ EnsurePeer();
TestStunServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
// Sets an additional stun server
peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
TestStunServer::GetInstance()->port());
}
// NB: Only does substring matching, watch out for stuff like "1.2.3.4"
// matching "21.2.3.47". " 1.2.3.4 " should not have false positives.
@@ -924,32 +977,45 @@ class IceConnectTest : public ::testing:
IceConnectTest() : initted_(false) {}
void SetUp() {
nsresult rv;
target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
ASSERT_TRUE(NS_SUCCEEDED(rv));
}
+ void TearDown() {
+ p1_ = nullptr;
+ p2_ = nullptr;
+
+ test_utils->sts_target()->Dispatch(WrapRunnable(this,
+ &IceConnectTest::TearDown_s),
+ NS_DISPATCH_SYNC);
+ }
+
+ void TearDown_s() {
+ NrIceCtx::internal_DeinitializeGlobal();
+ }
+
void AddStream(const std::string& name, int components) {
- Init(false);
+ Init(false, false);
p1_->AddStream(components);
p2_->AddStream(components);
}
- void Init(bool set_priorities) {
+ void Init(bool set_priorities, bool allow_loopback) {
if (!initted_) {
- p1_ = new IceTestPeer("P1", true, set_priorities);
- p2_ = new IceTestPeer("P2", false, set_priorities);
+ p1_ = new IceTestPeer("P1", true, set_priorities, allow_loopback);
+ p2_ = new IceTestPeer("P2", false, set_priorities, allow_loopback);
}
initted_ = true;
}
bool Gather(unsigned int waitTime = kDefaultTimeout) {
- Init(false);
+ Init(false, false);
p1_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
p2_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
p1_->Gather();
p2_->Gather();
if (waitTime) {
EXPECT_TRUE_WAIT(p1_->gathering_complete(), waitTime);
if (!p1_->gathering_complete())
@@ -1006,16 +1072,21 @@ class IceConnectTest : public ::testing:
}
void SetExpectedTypes(NrIceCandidate::Type local1, NrIceCandidate::Type remote1,
NrIceCandidate::Type local2, NrIceCandidate::Type remote2) {
p1_->SetExpectedTypes(local1, remote1);
p2_->SetExpectedTypes(local2, remote2);
}
+ void SetExpectedCandidateAddr(const std::string& addr) {
+ p1_->SetExpectedCandidateAddr(addr);
+ p2_->SetExpectedCandidateAddr(addr);
+ }
+
void ConnectP1(TrickleMode mode = TRICKLE_NONE) {
p1_->Connect(p2_, mode);
}
void ConnectP2(TrickleMode mode = TRICKLE_NONE) {
p2_->Connect(p1_, mode);
}
@@ -1141,21 +1212,34 @@ class PrioritizerTest : public ::testing
nr_interface_prioritizer *prioritizer_;
};
class PacketFilterTest : public ::testing::Test {
public:
PacketFilterTest(): filter_(nullptr) {}
void SetUp() {
+ // Set up enough of the ICE ctx to allow the packet filter to work
+ ice_ctx_ = NrIceCtx::Create("test", true);
+
nsCOMPtr<nsIUDPSocketFilterHandler> handler =
do_GetService(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID);
handler->NewFilter(getter_AddRefs(filter_));
}
+ void TearDown() {
+ test_utils->sts_target()->Dispatch(WrapRunnable(this,
+ &PacketFilterTest::TearDown_s),
+ NS_DISPATCH_SYNC);
+ }
+
+ void TearDown_s() {
+ ice_ctx_ = nullptr;
+ }
+
void TestIncoming(const uint8_t* data, uint32_t len,
uint8_t from_addr, int from_port,
bool expected_result) {
mozilla::net::NetAddr addr;
MakeNetAddr(&addr, from_addr, from_port);
bool result;
nsresult rv = filter_->FilterPacket(&addr, data, len,
nsIUDPSocketFilter::SF_INCOMING,
@@ -1181,91 +1265,114 @@ class PacketFilterTest : public ::testin
void MakeNetAddr(mozilla::net::NetAddr* net_addr,
uint8_t last_digit, uint16_t port) {
net_addr->inet.family = AF_INET;
net_addr->inet.ip = 192 << 24 | 168 << 16 | 1 << 8 | last_digit;
net_addr->inet.port = port;
}
nsCOMPtr<nsIUDPSocketFilter> filter_;
+ RefPtr<NrIceCtx> ice_ctx_;
};
} // end namespace
TEST_F(IceGatherTest, TestGatherFakeStunServerHostnameNoResolver) {
+ EnsurePeer();
peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
Gather();
}
TEST_F(IceGatherTest, TestGatherFakeStunServerIpAddress) {
+ EnsurePeer();
peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
peer_->SetFakeResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherFakeStunServerHostname) {
+ EnsurePeer();
peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
peer_->SetFakeResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherFakeStunBogusHostname) {
+ EnsurePeer();
peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
peer_->SetFakeResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddress) {
+ EnsurePeer();
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) {
+ EnsurePeer();
peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
peer_->SetDNSResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherDNSStunBogusHostname) {
+ EnsurePeer();
peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
peer_->SetDNSResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherTurn) {
+ EnsurePeer();
if (g_turn_server.empty())
return;
peer_->SetTurnServer(g_turn_server, kDefaultStunServerPort,
g_turn_user, g_turn_password, kNrIceTransportUdp);
Gather();
}
TEST_F(IceGatherTest, TestGatherTurnTcp) {
+ EnsurePeer();
if (g_turn_server.empty())
return;
peer_->SetTurnServer(g_turn_server, kDefaultStunServerPort,
g_turn_user, g_turn_password, kNrIceTransportTcp);
Gather();
}
TEST_F(IceGatherTest, TestGatherDisableComponent) {
+ EnsurePeer();
peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort);
peer_->AddStream(2);
peer_->DisableComponent(1, 2);
Gather();
std::vector<std::string> candidates =
peer_->GetCandidates(1);
for (size_t i=0; i<candidates.size(); ++i) {
size_t sp1 = candidates[i].find(' ');
ASSERT_EQ(0, candidates[i].compare(sp1+1, 1, "1", 1));
}
}
+TEST_F(IceGatherTest, TestGatherVerifyNoLoopback) {
+ Gather();
+ ASSERT_FALSE(StreamHasMatchingCandidate(0, "127.0.0.1"));
+}
+
+TEST_F(IceGatherTest, TestGatherAllowLoopback) {
+ // Set up peer with loopback allowed.
+ peer_ = new IceTestPeer("P1", true, false, true);
+ peer_->AddStream(1);
+ Gather();
+ ASSERT_TRUE(StreamHasMatchingCandidate(0, "127.0.0.1"));
+}
// Verify that a bogus candidate doesn't cause crashes on the
// main thread. See bug 856433.
TEST_F(IceGatherTest, TestBogusCandidate) {
Gather();
peer_->ParseCandidate(0, kBogusIceCandidate);
}
@@ -1304,28 +1411,38 @@ TEST_F(IceGatherTest, TestStunServerTric
}
TEST_F(IceConnectTest, TestGather) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
}
TEST_F(IceConnectTest, TestGatherAutoPrioritize) {
- Init(false);
+ Init(false, false);
AddStream("first", 1);
ASSERT_TRUE(Gather());
}
TEST_F(IceConnectTest, TestConnect) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
Connect();
}
+TEST_F(IceConnectTest, TestLoopbackOnlySortOf) {
+ Init(false, true);
+ AddStream("first", 1);
+ ASSERT_TRUE(Gather());
+ SetCandidateFilter(IsLoopbackCandidate);
+ SetExpectedCandidateAddr("127.0.0.1");
+ Connect();
+}
+
+
TEST_F(IceConnectTest, TestConnectBothControllingP1Wins) {
AddStream("first", 1);
p1_->SetTiebreaker(1);
p2_->SetTiebreaker(0);
ASSERT_TRUE(Gather());
p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
Connect();
@@ -1432,17 +1549,17 @@ TEST_F(IceConnectTest, TestConnectP2Then
std::cerr << "Sleeping between trickle streams" << std::endl;
PR_Sleep(1000); // Give this some time to settle but not complete
// all of ICE.
SimulateTrickleP1(1);
WaitForComplete(2);
}
TEST_F(IceConnectTest, TestConnectAutoPrioritize) {
- Init(false);
+ Init(false, false);
AddStream("first", 1);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(IceConnectTest, TestConnectTrickleOneStreamOneComponent) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
@@ -1750,17 +1867,16 @@ TEST_F(IceConnectTest, TestPollCandPairs
WaitForComplete();
p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
ASSERT_TRUE(ContainsSucceededPair(pairs1));
ASSERT_TRUE(ContainsSucceededPair(pairs2));
}
TEST_F(IceConnectTest, TestRLogRingBuffer) {
- RLogRingBuffer::CreateInstance();
AddStream("first", 1);
ASSERT_TRUE(Gather());
p2_->Connect(p1_, TRICKLE_NONE, false);
p1_->Connect(p2_, TRICKLE_NONE, false);
std::vector<NrIceCandidatePair> pairs1;
std::vector<NrIceCandidatePair> pairs2;
@@ -1789,18 +1905,16 @@ TEST_F(IceConnectTest, TestRLogRingBuffe
for (auto p = pairs2.begin(); p != pairs2.end(); ++p) {
std::deque<std::string> logs;
std::string substring("CAND-PAIR(");
substring += p->codeword;
RLogRingBuffer::GetInstance()->Filter(substring, 0, &logs);
ASSERT_NE(0U, logs.size());
}
-
- RLogRingBuffer::DestroyInstance();
}
TEST_F(PrioritizerTest, TestPrioritizer) {
SetPriorizer(::mozilla::CreateInterfacePrioritizer());
AddInterface("0", NR_INTERFACE_TYPE_VPN, 100); // unknown vpn
AddInterface("1", NR_INTERFACE_TYPE_VPN | NR_INTERFACE_TYPE_WIRED, 100); // wired vpn
AddInterface("2", NR_INTERFACE_TYPE_VPN | NR_INTERFACE_TYPE_WIFI, 100); // wifi vpn
--- a/media/mtransport/test/turn_unittest.cpp
+++ b/media/mtransport/test/turn_unittest.cpp
@@ -401,17 +401,17 @@ int main(int argc, char **argv)
NSS_NoDB_Init(nullptr);
NSS_SetDomesticPolicy();
// Set up the ICE registry, etc.
// TODO(ekr@rtfm.com): Clean up
std::string dummy("dummy");
RUN_ON_THREAD(test_utils->sts_target(),
WrapRunnableNM(&NrIceCtx::Create,
- dummy, false, false),
+ dummy, false, false, false),
NS_DISPATCH_SYNC);
// Start the tests
::testing::InitGoogleTest(&argc, argv);
int rv = RUN_ALL_TESTS();
delete test_utils;
return rv;
--- a/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c
@@ -43,19 +43,23 @@ static char *RCSSTRING __UNUSED__="$Id:
#include "stun_reg.h"
#include "nr_crypto.h"
#include "r_time.h"
static int nr_stun_client_send_request(nr_stun_client_ctx *ctx);
static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg);
static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password);
+#define NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD 1
+#define NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK 2
+
int nr_stun_client_ctx_create(char *label, nr_socket *sock, nr_transport_addr *peer, UINT4 RTO, nr_stun_client_ctx **ctxp)
{
nr_stun_client_ctx *ctx=0;
+ char allow_loopback;
int r,_status;
if ((r=nr_stun_startup()))
ABORT(r);
if(!(ctx=RCALLOC(sizeof(nr_stun_client_ctx))))
ABORT(R_NO_MEMORY);
@@ -80,16 +84,22 @@ int nr_stun_client_ctx_create(char *labe
ctx->retransmission_backoff_factor = 2.0;
if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS, &ctx->maximum_transmits))
ctx->maximum_transmits = 7;
if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF, &ctx->final_retransmit_backoff_ms))
ctx->final_retransmit_backoff_ms = 16 * ctx->rto_ms;
+ ctx->mapped_addr_check_mask = NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD;
+ if (NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, &allow_loopback) ||
+ !allow_loopback) {
+ ctx->mapped_addr_check_mask |= NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK;
+ }
+
/* If we are doing TCP, compute the maximum timeout as if
we retransmitted and then set the maximum number of
transmits to 1 and the timeout to maximum timeout*/
if (ctx->my_addr.protocol == IPPROTO_TCP) {
ctx->timeout_ms = ctx->final_retransmit_backoff_ms;
ctx->maximum_transmits = 1;
}
@@ -406,22 +416,22 @@ static int nr_stun_client_send_request(n
static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password)
{
*password = (Data*)arg;
if (!arg)
return(R_NOT_FOUND);
return(0);
}
-int nr_stun_transport_addr_check(nr_transport_addr* addr)
+int nr_stun_transport_addr_check(nr_transport_addr* addr, UINT4 check)
{
- if(nr_transport_addr_is_wildcard(addr))
+ if((check & NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD) && nr_transport_addr_is_wildcard(addr))
return(R_BAD_DATA);
- if (nr_transport_addr_is_loopback(addr))
+ if ((check & NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK) && nr_transport_addr_is_loopback(addr))
return(R_BAD_DATA);
return(0);
}
int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr)
{
int r,_status;
@@ -639,17 +649,18 @@ int nr_stun_client_process_response(nr_s
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
ABORT(R_BAD_DATA);
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
ABORT(R_BAD_DATA);
if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_RELAY_ADDRESS, &attr))
ABORT(R_BAD_DATA);
- if ((r=nr_stun_transport_addr_check(&attr->u.relay_address.unmasked)))
+ if ((r=nr_stun_transport_addr_check(&attr->u.relay_address.unmasked,
+ ctx->mapped_addr_check_mask)))
ABORT(r);
if ((r=nr_transport_addr_copy(
&ctx->results.allocate_response.relay_addr,
&attr->u.relay_address.unmasked)))
ABORT(r);
if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr))
@@ -683,24 +694,26 @@ int nr_stun_client_process_response(nr_s
/* make sure we have the most up-to-date address from this peer */
if (nr_transport_addr_cmp(&ctx->peer_addr, peer_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Peer moved from %s to %s", ctx->label, ctx->peer_addr.as_string, peer_addr->as_string);
nr_transport_addr_copy(&ctx->peer_addr, peer_addr);
}
if (mapped_addr) {
if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, &attr)) {
- if ((r=nr_stun_transport_addr_check(&attr->u.xor_mapped_address.unmasked)))
+ if ((r=nr_stun_transport_addr_check(&attr->u.xor_mapped_address.unmasked,
+ ctx->mapped_addr_check_mask)))
ABORT(r);
if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.xor_mapped_address.unmasked)))
ABORT(r);
}
else if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, &attr)) {
- if ((r=nr_stun_transport_addr_check(&attr->u.mapped_address)))
+ if ((r=nr_stun_transport_addr_check(&attr->u.mapped_address,
+ ctx->mapped_addr_check_mask)))
ABORT(r);
if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.mapped_address)))
ABORT(r);
}
else
ABORT(R_BAD_DATA);
--- a/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.h
@@ -167,30 +167,31 @@ struct nr_stun_client_ctx_ {
char *nonce;
char *realm;
void *timer_handle;
int request_ct;
UINT4 rto_ms; /* retransmission time out */
double retransmission_backoff_factor;
UINT4 maximum_transmits;
UINT4 final_retransmit_backoff_ms;
+ UINT4 mapped_addr_check_mask; /* What checks to run on mapped addresses */
int timeout_ms;
struct timeval timer_set;
int retry_ct;
NR_async_cb finished_cb;
void *cb_arg;
nr_stun_message *request;
nr_stun_message *response;
UINT2 error_code;
};
int nr_stun_client_ctx_create(char *label, nr_socket *sock, nr_transport_addr *peer, UINT4 RTO, nr_stun_client_ctx **ctxp);
int nr_stun_client_start(nr_stun_client_ctx *ctx, int mode, NR_async_cb finished_cb, void *cb_arg);
int nr_stun_client_restart(nr_stun_client_ctx *ctx);
int nr_stun_client_force_retransmit(nr_stun_client_ctx *ctx);
int nr_stun_client_reset(nr_stun_client_ctx *ctx);
int nr_stun_client_ctx_destroy(nr_stun_client_ctx **ctxp);
-int nr_stun_transport_addr_check(nr_transport_addr* addr);
+int nr_stun_transport_addr_check(nr_transport_addr* addr, UINT4 mask);
int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr);
int nr_stun_client_cancel(nr_stun_client_ctx *ctx);
#endif
--- a/media/mtransport/third_party/nICEr/src/stun/stun_reg.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_reg.h
@@ -39,16 +39,17 @@ using namespace std;
extern "C" {
#endif /* __cplusplus */
#define NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT "stun.client.retransmission_timeout"
#define NR_STUN_REG_PREF_CLNT_RETRANSMIT_BACKOFF "stun.client.retransmission_backoff_factor"
#define NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS "stun.client.maximum_transmits"
#define NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF "stun.client.final_retransmit_backoff"
+#define NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS "stun.allow_loopback"
#define NR_STUN_REG_PREF_ADDRESS_PRFX "stun.address"
#define NR_STUN_REG_PREF_SERVER_NAME "stun.server.name"
#define NR_STUN_REG_PREF_SERVER_NONCE_SIZE "stun.server.nonce_size"
#define NR_STUN_REG_PREF_SERVER_REALM "stun.server.realm"
#ifdef __cplusplus
}
#endif /* __cplusplus */
--- a/media/mtransport/third_party/nICEr/src/stun/stun_util.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_util.c
@@ -105,17 +105,26 @@ nr_stun_find_local_addresses(nr_local_ad
if ((r=NR_reg_get_child_count(NR_STUN_REG_PREF_ADDRESS_PRFX, (unsigned int*)count)))
if (r == R_NOT_FOUND)
*count = 0;
else
ABORT(r);
if (*count == 0) {
- if ((r=nr_stun_get_addrs(addrs, maxaddrs, 1, count)))
+ char allow_loopback;
+
+ if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, &allow_loopback))) {
+ if (r == R_NOT_FOUND)
+ allow_loopback = 0;
+ else
+ ABORT(r);
+ }
+
+ if ((r=nr_stun_get_addrs(addrs, maxaddrs, !allow_loopback, count)))
ABORT(r);
goto done;
}
if (*count >= maxaddrs) {
r_log(NR_LOG_STUN, LOG_INFO, "Address list truncated from %d to %d", *count, maxaddrs);
*count = maxaddrs;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -199,19 +199,29 @@ PeerConnectionMedia::PeerConnectionMedia
mIceCtx(nullptr),
mDNSResolver(new mozilla::NrIceResolver()),
mMainThread(mParent->GetMainThread()),
mSTSThread(mParent->GetSTSThread()) {}
nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers,
const std::vector<NrIceTurnServer>& turn_servers)
{
+#ifdef MOZILLA_INTERNAL_API
+ bool allow_loopback = Preferences::GetBool(
+ "media.peerconnection.ice.loopback", false);
+#else
+ bool allow_loopback = false;
+#endif
+
// TODO(ekr@rtfm.com): need some way to set not offerer later
// Looks like a bug in the NrIceCtx API.
- mIceCtx = NrIceCtx::Create("PC:" + mParent->GetName(), true);
+ mIceCtx = NrIceCtx::Create("PC:" + mParent->GetName(),
+ true, // Offerer
+ true, // Trickle
+ allow_loopback);
if(!mIceCtx) {
CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
return NS_ERROR_FAILURE;
}
nsresult rv;
if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) {
CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__);
return rv;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -332,16 +332,17 @@ pref("media.getusermedia.browser.enabled
// Desktop is typically VGA capture or more; and qm_select will not drop resolution
// below 1/2 in each dimension (or so), so QVGA (320x200) is the lowest here usually.
pref("media.peerconnection.video.min_bitrate", 200);
pref("media.peerconnection.video.start_bitrate", 300);
pref("media.peerconnection.video.max_bitrate", 2000);
#endif
pref("media.navigator.permission.disabled", false);
pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:stun.services.mozilla.com\"}]");
+pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
pref("media.peerconnection.use_document_iceservers", true);
// Do not enable identity before ensuring that the UX cannot be spoofed
// see Bug 884573 for details
// Do not enable identity before fixing domain comparison: see Bug 958741
// Do not enable identity before fixing origin spoofing: see Bug 968335
pref("media.peerconnection.identity.enabled", false);
pref("media.peerconnection.identity.timeout", 10000);
// These values (aec, agc, and noice) are from media/webrtc/trunk/webrtc/common_types.h