--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -659,16 +659,20 @@ int NrIceCtx::SetNat(const RefPtr<TestNa
void NrIceCtx::internal_DeinitializeGlobal() {
NR_reg_del((char *)"stun");
NR_reg_del((char *)"ice");
RLogRingBuffer::DestroyInstance();
nr_crypto_vtbl = nullptr;
initialized = false;
}
+void NrIceCtx::internal_SetTimerAccelarator(int divider) {
+ ctx_->test_timer_divider = divider;
+}
+
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
@@ -226,16 +226,18 @@ class NrIceCtx {
const std::string& ufrag,
const std::string& pwd);
int SetNat(const RefPtr<TestNat>& aNat);
// Deinitialize all ICE global state. Used only for testing.
static void internal_DeinitializeGlobal();
+ // Divide some timers to faster testing. Used only for testing.
+ void internal_SetTimerAccelarator(int divider);
nr_ice_ctx *ctx() { return ctx_; }
nr_ice_peer_ctx *peer() { return peer_; }
// Testing only.
void destroy_peer_ctx();
void SetStream(size_t index, NrIceMediaStream* stream);
--- a/media/mtransport/nricemediastream.cpp
+++ b/media/mtransport/nricemediastream.cpp
@@ -529,16 +529,41 @@ nsresult NrIceMediaStream::DisableCompon
MOZ_MTLOG(ML_ERROR, "Couldn't disable '" << name_ << "':" <<
component_id);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
+nsresult NrIceMediaStream::GetConsentStatus(int component_id, bool *can_send, struct timeval *ts) {
+ if (!stream_)
+ return NS_ERROR_FAILURE;
+
+ nr_ice_media_stream* peer_stream;
+ int r = nr_ice_peer_ctx_find_pstream(ctx_peer_, stream_, &peer_stream);
+ if (r) {
+ MOZ_MTLOG(ML_ERROR, "Failed to find peer stream for '" << name_ << "':" <<
+ component_id);
+ return NS_ERROR_FAILURE;
+ }
+
+ int send = 0;
+ r = nr_ice_media_stream_get_consent_status(peer_stream, component_id,
+ &send, ts);
+ if (r) {
+ MOZ_MTLOG(ML_ERROR, "Failed to get consent status for '" << name_ << "':" <<
+ component_id);
+ return NS_ERROR_FAILURE;
+ }
+ *can_send = !!send;
+
+ return NS_OK;
+}
+
nsresult NrIceMediaStream::SendPacket(int component_id,
const unsigned char *data,
size_t len) {
if (!stream_)
return NS_ERROR_FAILURE;
int r = nr_ice_media_stream_send(ctx_peer_, stream_,
component_id,
--- a/media/mtransport/nricemediastream.h
+++ b/media/mtransport/nricemediastream.h
@@ -159,16 +159,20 @@ class NrIceMediaStream {
nsresult DisableComponent(int component);
// Get the candidate pair currently active. It's the
// caller's responsibility to free these.
nsresult GetActivePair(int component,
UniquePtr<NrIceCandidate>* local,
UniquePtr<NrIceCandidate>* remote);
+ // Get the current ICE consent send status plus the timeval of the last
+ // consent update time.
+ nsresult GetConsentStatus(int component, bool *can_send, struct timeval *ts);
+
// The number of components
size_t components() const { return components_; }
// The underlying nICEr stream
nr_ice_media_stream *stream() { return stream_; }
// Signals to indicate events. API users can (and should)
// register for these.
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -43,27 +43,26 @@
#include "ice_ctx.h"
#include "ice_peer_ctx.h"
#include "ice_media_stream.h"
extern "C" {
#include "async_timer.h"
#include "r_data.h"
#include "util.h"
+#include "r_time.h"
}
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
#include "gtest_utils.h"
using namespace mozilla;
-bool stream_added = false;
-
static unsigned int kDefaultTimeout = 7000;
//TODO(nils@mozilla.com): This should get replaced with some non-external
//solution like discussed in bug 860775.
const std::string kDefaultStunServerHostname(
(char *)"global.stun.twilio.com");
const std::string kBogusStunServerHostname(
(char *)"stun-server-nonexistent.invalid");
@@ -173,16 +172,18 @@ public:
RLogRingBuffer::DestroyInstance();
MtransportTest::TearDown();
}
};
enum TrickleMode { TRICKLE_NONE, TRICKLE_SIMULATE, TRICKLE_REAL };
+enum ConsentStatus { CONSENT_FRESH, CONSENT_STALE, CONSENT_EXPIRED};
+
const unsigned int ICE_TEST_PEER_OFFERER = (1 << 0);
const unsigned int ICE_TEST_PEER_ALLOW_LOOPBACK = (1 << 1);
const unsigned int ICE_TEST_PEER_ENABLED_TCP = (1 << 2);
const unsigned int ICE_TEST_PEER_ALLOW_LINK_LOCAL = (1 << 3);
const unsigned int ICE_TEST_PEER_HIDE_NON_DEFAULT = (1 << 4);
typedef std::string (*CandidateFilter)(const std::string& candidate);
@@ -407,16 +408,18 @@ class IceTestPeer : public sigslot::has_
test_utils_(utils) {
ice_ctx_->ctx()->SignalGatheringStateChange.connect(
this,
&IceTestPeer::GatheringStateChange);
ice_ctx_->ctx()->SignalConnectionStateChange.connect(
this,
&IceTestPeer::ConnectionStateChange);
+ consent_timestamp_.tv_sec = 0;
+ consent_timestamp_.tv_usec = 0;
int r = ice_ctx_->ctx()->SetNat(nat_);
(void)r;
MOZ_ASSERT(!r);
}
~IceTestPeer() {
test_utils_->sts_target()->Dispatch(WrapRunnable(this,
&IceTestPeer::Shutdown),
@@ -536,31 +539,43 @@ class IceTestPeer : public sigslot::has_
ASSERT_TRUE(NS_SUCCEEDED(res));
}
void UseNat() {
nat_->enabled_ = true;
}
+ void SetTimerDivider(int div) {
+ ice_ctx_->ctx()->internal_SetTimerAccelarator(div);
+ }
+
+ void SetStunResponseDelay(uint32_t delay) {
+ nat_->delay_stun_resp_ms_ = delay;
+ }
+
void SetFilteringType(TestNat::NatBehavior type) {
MOZ_ASSERT(!nat_->has_port_mappings());
nat_->filtering_type_ = type;
}
void SetMappingType(TestNat::NatBehavior type) {
MOZ_ASSERT(!nat_->has_port_mappings());
nat_->mapping_type_ = type;
}
void SetBlockUdp(bool block) {
MOZ_ASSERT(!nat_->has_port_mappings());
nat_->block_udp_ = block;
}
+ void SetBlockStun(bool block) {
+ nat_->block_stun_ = block;
+ }
+
// Get various pieces of state
std::vector<std::string> GetGlobalAttributes() {
std::vector<std::string> attrs(ice_ctx_->ctx()->GetGlobalAttributes());
if (simulate_ice_lite_) {
attrs.push_back("ice-lite");
}
return attrs;
}
@@ -1227,16 +1242,30 @@ class IceTestPeer : public sigslot::has_
}
ASSERT_TRUE(NS_SUCCEEDED(media_stream->SendPacket(component, data, len)));
++sent_;
std::cerr << name_ << ": sent " << len << " bytes" << std::endl;
}
+ void SendFailure(int stream, int component) {
+ RefPtr<NrIceMediaStream> media_stream = ice_ctx_->ctx()->GetStream(stream);
+ if (!media_stream) {
+ ADD_FAILURE() << "No such stream " << stream;
+ return;
+ }
+
+ const std::string d("FAIL");
+ ASSERT_TRUE(NS_FAILED(media_stream->SendPacket(component,
+ reinterpret_cast<const unsigned char *>(d.c_str()), d.length())));
+
+ std::cerr << name_ << ": send failed as expected" << std::endl;
+ }
+
void SetCandidateFilter(CandidateFilter filter) {
candidate_filter_ = filter;
}
void ParseCandidate_s(size_t i, const std::string& candidate) {
ASSERT_TRUE(ice_ctx_->ctx()->GetStream(i).get()) << "No such stream " << i;
std::vector<std::string> attributes;
@@ -1269,16 +1298,54 @@ class IceTestPeer : public sigslot::has_
test_utils_->sts_target()->Dispatch(
WrapRunnable(this,
&IceTestPeer::DisableComponent_s,
stream,
component_id),
NS_DISPATCH_SYNC);
}
+ void AssertConsentRefresh_s(size_t stream, int component_id, ConsentStatus status) {
+ ASSERT_LT(stream, ice_ctx_->ctx()->GetStreamCount());
+ ASSERT_TRUE(ice_ctx_->ctx()->GetStream(stream).get()) << "No such stream "
+ << stream;
+ bool can_send;
+ struct timeval timestamp;
+ nsresult res = ice_ctx_->ctx()->GetStream(stream)->
+ GetConsentStatus(component_id, &can_send, ×tamp);
+ ASSERT_TRUE(NS_SUCCEEDED(res));
+ if (status == CONSENT_EXPIRED) {
+ ASSERT_EQ(can_send, 0);
+ } else {
+ ASSERT_EQ(can_send, 1);
+ }
+ if (consent_timestamp_.tv_sec) {
+ if (status == CONSENT_FRESH) {
+ ASSERT_EQ(r_timeval_cmp(×tamp, &consent_timestamp_), 1);
+ } else {
+ ASSERT_EQ(r_timeval_cmp(×tamp, &consent_timestamp_), 0);
+ }
+ }
+ consent_timestamp_.tv_sec = timestamp.tv_sec;
+ consent_timestamp_.tv_usec = timestamp.tv_usec;
+ std::cerr << name_ << ": new consent timestamp = " <<
+ consent_timestamp_.tv_sec << "." << consent_timestamp_.tv_usec <<
+ std::endl;
+ }
+
+ void AssertConsentRefresh(ConsentStatus status) {
+ test_utils_->sts_target()->Dispatch(
+ WrapRunnable(this,
+ &IceTestPeer::AssertConsentRefresh_s,
+ 0,
+ 1,
+ status),
+ NS_DISPATCH_SYNC);
+ }
+
int trickled() { return trickled_; }
void SetControlling(NrIceCtx::Controlling controlling) {
nsresult res;
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res, ice_ctx_->ctx(),
&NrIceCtx::SetControlling,
controlling),
@@ -1327,16 +1394,17 @@ class IceTestPeer : public sigslot::has_
std::map<size_t, std::vector<SchedulableTrickleCandidate*> >
controlled_trickle_candidates_;
bool gathering_complete_;
int ready_ct_;
bool ice_complete_;
bool ice_reached_checking_;
size_t received_;
size_t sent_;
+ struct timeval consent_timestamp_;
NrIceResolverFake fake_resolver_;
RefPtr<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_remote_addr_;
@@ -1540,17 +1608,17 @@ class WebRtcIceConnectTest : public Stun
void TearDown() override {
p1_ = nullptr;
p2_ = nullptr;
StunTest::TearDown();
}
- void AddStream(const std::string& name, int components) {
+ void AddStream(int components) {
Init(false, false);
p1_->AddStream(components);
p2_->AddStream(components);
}
void RemoveStream(size_t index) {
p1_->RemoveStream(index);
p2_->RemoveStream(index);
@@ -1642,16 +1710,31 @@ class WebRtcIceConnectTest : public Stun
}
void BlockUdp() {
// note: |block_udp_| is used only in InitPeer.
// Use IceTestPeer::SetBlockUdp to act on the peer directly.
block_udp_ = true;
}
+ void SetupAndCheckConsent() {
+ p1_->SetTimerDivider(10);
+ p2_->SetTimerDivider(10);
+ ASSERT_TRUE(Gather());
+ Connect();
+ p1_->AssertConsentRefresh(CONSENT_FRESH);
+ p2_->AssertConsentRefresh(CONSENT_FRESH);
+ SendReceive();
+ }
+
+ void AssertConsentRefresh(ConsentStatus status = CONSENT_FRESH) {
+ p1_->AssertConsentRefresh(status);
+ p2_->AssertConsentRefresh(status);
+ }
+
void InitTestStunServer() {
if (test_stun_server_inited_) {
return;
}
std::cerr << "Resetting TestStunServer" << std::endl;
TestStunServer::GetInstance(AF_INET)->Reset();
test_stun_server_inited_ = true;
@@ -1820,16 +1903,23 @@ class WebRtcIceConnectTest : public Stun
if (expect_rx_failure) {
usleep(1000);
ASSERT_EQ(previousReceived, p2->received());
} else {
ASSERT_TRUE_WAIT(p2->received() == previousReceived+1, 1000);
}
}
+ void SendFailure() {
+ test_utils_->sts_target()->Dispatch(
+ WrapRunnable(p1_.get(),
+ &IceTestPeer::SendFailure, 0, 1),
+ NS_DISPATCH_SYNC);
+ }
+
protected:
bool initted_;
bool test_stun_server_inited_;
nsCOMPtr<nsIEventTarget> target_;
mozilla::UniquePtr<IceTestPeer> p1_;
mozilla::UniquePtr<IceTestPeer> p2_;
bool use_nat_;
TestNat::NatBehavior filtering_type_;
@@ -2393,42 +2483,42 @@ TEST_F(WebRtcIceGatherTest, TestStunTcpA
ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
WaitForGather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
}
TEST_F(WebRtcIceConnectTest, TestGather) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
}
TEST_F(WebRtcIceConnectTest, TestGatherTcp) {
Init(false, true);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
}
TEST_F(WebRtcIceConnectTest, TestGatherAutoPrioritize) {
Init(false, false);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
}
TEST_F(WebRtcIceConnectTest, TestConnect) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectRestartIce) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
Connect();
SendReceive(p1_.get(), p2_.get());
p2_->RestartIce();
ASSERT_FALSE(p2_->gathering_complete());
// verify p1 and p2 streams are still connected after restarting ice on p2
@@ -2452,17 +2542,17 @@ TEST_F(WebRtcIceConnectTest, TestConnect
SendReceive(p1_.get(), p2_.get(), false, true); // p1 and p2 not connected
p3_ = nullptr;
}
TEST_F(WebRtcIceConnectTest, TestConnectRestartIceThenAbort) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
Connect();
SendReceive(p1_.get(), p2_.get());
p2_->RestartIce();
ASSERT_FALSE(p2_->gathering_complete());
// verify p1 and p2 streams are still connected after restarting ice on p2
@@ -2487,238 +2577,238 @@ TEST_F(WebRtcIceConnectTest, TestConnect
SendReceive(p3_.get(), p2_.get(), false, true); // p3 and p2 not connected
p3_ = nullptr;
}
TEST_F(WebRtcIceConnectTest, TestConnectTcp) {
Init(false, true);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsTcpCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
Connect();
}
//TCP SO tests works on localhost only with delay applied:
// tc qdisc add dev lo root netem delay 10ms
TEST_F(WebRtcIceConnectTest, DISABLED_TestConnectTcpSo) {
Init(false, true);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsTcpSoCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
Connect();
}
// Disabled because this breaks with hairpinning.
TEST_F(WebRtcIceConnectTest, DISABLED_TestConnectDefaultRouteOnly) {
Init(false, false, true);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
NrIceCandidate::Type::ICE_SERVER_REFLEXIVE, kNrIceTransportTcp);
Connect();
}
TEST_F(WebRtcIceConnectTest, TestLoopbackOnlySortOf) {
Init(true, false, false, false);
- AddStream("first", 1);
+ AddStream(1);
SetCandidateFilter(IsLoopbackCandidate);
ASSERT_TRUE(Gather());
SetExpectedRemoteCandidateAddr("127.0.0.1");
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectBothControllingP1Wins) {
- AddStream("first", 1);
+ AddStream(1);
p1_->SetTiebreaker(1);
p2_->SetTiebreaker(0);
ASSERT_TRUE(Gather());
p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectBothControllingP2Wins) {
- AddStream("first", 1);
+ AddStream(1);
p1_->SetTiebreaker(0);
p2_->SetTiebreaker(1);
ASSERT_TRUE(Gather());
p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectIceLiteOfferer) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
p1_->SimulateIceLite();
Connect();
}
TEST_F(WebRtcIceConnectTest, TestTrickleBothControllingP1Wins) {
- AddStream("first", 1);
+ AddStream(1);
p1_->SetTiebreaker(1);
p2_->SetTiebreaker(0);
ASSERT_TRUE(Gather());
p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
ConnectTrickle();
SimulateTrickle(0);
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, TestTrickleBothControllingP2Wins) {
- AddStream("first", 1);
+ AddStream(1);
p1_->SetTiebreaker(0);
p2_->SetTiebreaker(1);
ASSERT_TRUE(Gather());
p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
ConnectTrickle();
SimulateTrickle(0);
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, TestTrickleIceLiteOfferer) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
p1_->SimulateIceLite();
ConnectTrickle();
SimulateTrickle(0);
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, TestGatherFullCone) {
UseNat();
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
}
TEST_F(WebRtcIceConnectTest, TestGatherFullConeAutoPrioritize) {
UseNat();
Init(true, false);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
}
TEST_F(WebRtcIceConnectTest, TestConnectFullCone) {
UseNat();
- AddStream("first", 1);
+ AddStream(1);
SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectNoNatRouteOnly) {
Init(false, false, true, false);
- AddStream("first", 1);
+ AddStream(1);
UseTestStunServer();
// Because we are connecting from our host candidate to the
// other side's apparent srflx (which is also their host)
// we see a host/srflx pair.
SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectFullConeDefaultRouteOnly) {
UseNat();
Init(false, false, true);
- AddStream("first", 1);
+ AddStream(1);
SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestGatherAddressRestrictedCone) {
UseNat();
SetFilteringType(TestNat::ADDRESS_DEPENDENT);
SetMappingType(TestNat::ENDPOINT_INDEPENDENT);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
}
TEST_F(WebRtcIceConnectTest, TestConnectAddressRestrictedCone) {
UseNat();
SetFilteringType(TestNat::ADDRESS_DEPENDENT);
SetMappingType(TestNat::ENDPOINT_INDEPENDENT);
- AddStream("first", 1);
+ AddStream(1);
SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestGatherPortRestrictedCone) {
UseNat();
SetFilteringType(TestNat::PORT_DEPENDENT);
SetMappingType(TestNat::ENDPOINT_INDEPENDENT);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
}
TEST_F(WebRtcIceConnectTest, TestConnectPortRestrictedCone) {
UseNat();
SetFilteringType(TestNat::PORT_DEPENDENT);
SetMappingType(TestNat::ENDPOINT_INDEPENDENT);
- AddStream("first", 1);
+ AddStream(1);
SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestGatherSymmetricNat) {
UseNat();
SetFilteringType(TestNat::PORT_DEPENDENT);
SetMappingType(TestNat::PORT_DEPENDENT);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
}
TEST_F(WebRtcIceConnectTest, TestConnectSymmetricNat) {
if (turn_server_.empty())
return;
UseNat();
SetFilteringType(TestNat::PORT_DEPENDENT);
SetMappingType(TestNat::PORT_DEPENDENT);
- AddStream("first", 1);
+ AddStream(1);
p1_->SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
NrIceCandidate::Type::ICE_RELAYED);
p2_->SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
NrIceCandidate::Type::ICE_RELAYED);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestGatherNatBlocksUDP) {
if (turn_server_.empty())
return;
UseNat();
BlockUdp();
- AddStream("first", 1);
+ AddStream(1);
std::vector<NrIceTurnServer> turn_servers;
std::vector<unsigned char> password_vec(turn_password_.begin(),
turn_password_.end());
turn_servers.push_back(
*NrIceTurnServer::Create(turn_server_, kDefaultStunServerPort,
turn_user_, password_vec, kNrIceTransportTcp));
turn_servers.push_back(
*NrIceTurnServer::Create(turn_server_, kDefaultStunServerPort,
@@ -2729,17 +2819,17 @@ TEST_F(WebRtcIceConnectTest, TestGatherN
}
TEST_F(WebRtcIceConnectTest, TestConnectNatBlocksUDP) {
if (turn_server_.empty())
return;
UseNat();
BlockUdp();
- AddStream("first", 1);
+ AddStream(1);
std::vector<NrIceTurnServer> turn_servers;
std::vector<unsigned char> password_vec(turn_password_.begin(),
turn_password_.end());
turn_servers.push_back(
*NrIceTurnServer::Create(turn_server_, kDefaultStunServerPort,
turn_user_, password_vec, kNrIceTransportTcp));
turn_servers.push_back(
*NrIceTurnServer::Create(turn_server_, kDefaultStunServerPort,
@@ -2751,84 +2841,84 @@ TEST_F(WebRtcIceConnectTest, TestConnect
p2_->SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
NrIceCandidate::Type::ICE_RELAYED,
kNrIceTransportTcp);
ASSERT_TRUE(Gather(kDefaultTimeout * 3));
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectTwoComponents) {
- AddStream("first", 2);
+ AddStream(2);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectTwoComponentsDisableSecond) {
- AddStream("first", 2);
+ AddStream(2);
ASSERT_TRUE(Gather());
p1_->DisableComponent(0, 2);
p2_->DisableComponent(0, 2);
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectP2ThenP1) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectP2();
PR_Sleep(1000);
ConnectP1();
WaitForComplete();
}
TEST_F(WebRtcIceConnectTest, TestConnectP2ThenP1Trickle) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectP2();
PR_Sleep(1000);
ConnectP1(TRICKLE_SIMULATE);
SimulateTrickleP1(0);
WaitForComplete();
}
TEST_F(WebRtcIceConnectTest, TestConnectP2ThenP1TrickleTwoComponents) {
- AddStream("first", 1);
- AddStream("second", 2);
+ AddStream(1);
+ AddStream(2);
ASSERT_TRUE(Gather());
ConnectP2();
PR_Sleep(1000);
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.
SimulateTrickleP1(1);
WaitForComplete(2);
}
TEST_F(WebRtcIceConnectTest, TestConnectAutoPrioritize) {
Init(false, false);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectTrickleOneStreamOneComponent) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
SimulateTrickle(0);
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, TestConnectTrickleTwoStreamsOneComponent) {
- AddStream("first", 1);
- AddStream("second", 1);
+ AddStream(1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
SimulateTrickle(0);
SimulateTrickle(1);
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AssertCheckingReached();
}
@@ -2898,253 +2988,314 @@ void AddNonPairableCandidates(
}
}
void DropTrickleCandidates(
std::vector<SchedulableTrickleCandidate*>& candidates) {
}
TEST_F(WebRtcIceConnectTest, TestConnectTrickleAddStreamDuringICE) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
RealisticTrickleDelay(p2_->ControlTrickle(0));
- AddStream("second", 1);
+ AddStream(1);
RealisticTrickleDelay(p1_->ControlTrickle(1));
RealisticTrickleDelay(p2_->ControlTrickle(1));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, TestConnectTrickleAddStreamAfterICE) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
RealisticTrickleDelay(p2_->ControlTrickle(0));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
- AddStream("second", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(1));
RealisticTrickleDelay(p2_->ControlTrickle(1));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, RemoveStream) {
- AddStream("first", 1);
- AddStream("second", 1);
+ AddStream(1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
RealisticTrickleDelay(p2_->ControlTrickle(0));
RealisticTrickleDelay(p1_->ControlTrickle(1));
RealisticTrickleDelay(p2_->ControlTrickle(1));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
RemoveStream(0);
ASSERT_TRUE(Gather());
ConnectTrickle();
}
TEST_F(WebRtcIceConnectTest, P1NoTrickle) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
DropTrickleCandidates(p1_->ControlTrickle(0));
RealisticTrickleDelay(p2_->ControlTrickle(0));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
}
TEST_F(WebRtcIceConnectTest, P2NoTrickle) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
DropTrickleCandidates(p2_->ControlTrickle(0));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
}
TEST_F(WebRtcIceConnectTest, RemoveAndAddStream) {
- AddStream("first", 1);
- AddStream("second", 1);
+ AddStream(1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
RealisticTrickleDelay(p2_->ControlTrickle(0));
RealisticTrickleDelay(p1_->ControlTrickle(1));
RealisticTrickleDelay(p2_->ControlTrickle(1));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
RemoveStream(0);
- AddStream("third", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(2));
RealisticTrickleDelay(p2_->ControlTrickle(2));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
}
TEST_F(WebRtcIceConnectTest, RemoveStreamBeforeGather) {
- AddStream("first", 1);
- AddStream("second", 1);
+ AddStream(1);
+ AddStream(1);
ASSERT_TRUE(Gather(0));
RemoveStream(0);
WaitForGather();
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(1));
RealisticTrickleDelay(p2_->ControlTrickle(1));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
}
TEST_F(WebRtcIceConnectTest, RemoveStreamDuringGather) {
- AddStream("first", 1);
- AddStream("second", 1);
+ AddStream(1);
+ AddStream(1);
RemoveStream(0);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(1));
RealisticTrickleDelay(p2_->ControlTrickle(1));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
}
TEST_F(WebRtcIceConnectTest, RemoveStreamDuringConnect) {
- AddStream("first", 1);
- AddStream("second", 1);
+ AddStream(1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
RealisticTrickleDelay(p2_->ControlTrickle(0));
RealisticTrickleDelay(p1_->ControlTrickle(1));
RealisticTrickleDelay(p2_->ControlTrickle(1));
RemoveStream(0);
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
}
TEST_F(WebRtcIceConnectTest, TestConnectRealTrickleOneStreamOneComponent) {
- AddStream("first", 1);
- AddStream("second", 1);
+ AddStream(1);
+ AddStream(1);
ASSERT_TRUE(Gather(0));
ConnectTrickle(TRICKLE_REAL);
ASSERT_TRUE_WAIT(p1_->ice_complete(), kDefaultTimeout);
ASSERT_TRUE_WAIT(p2_->ice_complete(), kDefaultTimeout);
WaitForGather(); // ICE can complete before we finish gathering.
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, TestSendReceive) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
Connect();
SendReceive();
}
TEST_F(WebRtcIceConnectTest, TestSendReceiveTcp) {
Init(false, true);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsTcpCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
Connect();
SendReceive();
}
//TCP SO tests works on localhost only with delay applied:
// tc qdisc add dev lo root netem delay 10ms
TEST_F(WebRtcIceConnectTest, DISABLED_TestSendReceiveTcpSo) {
Init(false, true);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsTcpSoCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
Connect();
SendReceive();
}
+TEST_F(WebRtcIceConnectTest, TestConsent) {
+ AddStream(1);
+ SetupAndCheckConsent();
+ PR_Sleep(1500);
+ AssertConsentRefresh();
+ SendReceive();
+}
+
+TEST_F(WebRtcIceConnectTest, TestConsentTcp) {
+ Init(false, true);
+ AddStream(1);
+ SetCandidateFilter(IsTcpCandidate);
+ SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
+ NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
+ SetupAndCheckConsent();
+ PR_Sleep(1500);
+ AssertConsentRefresh();
+ SendReceive();
+}
+
+TEST_F(WebRtcIceConnectTest, TestConsentIntermittent) {
+ AddStream(1);
+ SetupAndCheckConsent();
+ p1_->SetBlockStun(true);
+ p2_->SetBlockStun(true);
+ PR_Sleep(1000);
+ AssertConsentRefresh(CONSENT_STALE);
+ SendReceive();
+ p1_->SetBlockStun(false);
+ p2_->SetBlockStun(false);
+ PR_Sleep(600);
+ AssertConsentRefresh();
+ SendReceive();
+}
+
+TEST_F(WebRtcIceConnectTest, TestConsentTimeout) {
+ AddStream(1);
+ SetupAndCheckConsent();
+ p1_->SetBlockStun(true);
+ p2_->SetBlockStun(true);
+ PR_Sleep(600);
+ AssertConsentRefresh(CONSENT_STALE);
+ SendReceive();
+ PR_Sleep(2500);
+ AssertConsentRefresh(CONSENT_EXPIRED);
+ SendFailure();
+}
+
+TEST_F(WebRtcIceConnectTest, TestConsentDelayed) {
+ AddStream(1);
+ SetupAndCheckConsent();
+ /* Note: We don't have a list of STUN transaction IDs of the previously timed
+ out consent requests. Thus responses after sending the next consent
+ request are ignored. */
+ p1_->SetStunResponseDelay(300);
+ p2_->SetStunResponseDelay(300);
+ PR_Sleep(1000);
+ AssertConsentRefresh();
+ SendReceive();
+}
+
TEST_F(WebRtcIceConnectTest, TestConnectTurn) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectTurnWithDelay) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_);
SetCandidateFilter(SabotageHostCandidateAndDropReflexive);
p1_->Gather();
PR_Sleep(500);
p2_->Gather();
ConnectTrickle(TRICKLE_REAL);
WaitForGather();
WaitForComplete();
}
TEST_F(WebRtcIceConnectTest, TestConnectTurnWithNormalTrickleDelay) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
RealisticTrickleDelay(p2_->ControlTrickle(0));
ASSERT_TRUE_WAIT(p1_->ice_complete(), kDefaultTimeout);
ASSERT_TRUE_WAIT(p2_->ice_complete(), kDefaultTimeout);
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, TestConnectTurnWithNormalTrickleDelayOneSided) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
p2_->SimulateTrickle(0);
ASSERT_TRUE_WAIT(p1_->ice_complete(), kDefaultTimeout);
ASSERT_TRUE_WAIT(p2_->ice_complete(), kDefaultTimeout);
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, TestConnectTurnWithLargeTrickleDelay) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_);
SetCandidateFilter(SabotageHostCandidateAndDropReflexive);
ASSERT_TRUE(Gather());
ConnectTrickle();
// Trickle host candidates immediately, but delay relay candidates
DelayRelayCandidates(p1_->ControlTrickle(0), 3700);
DelayRelayCandidates(p2_->ControlTrickle(0), 3700);
@@ -3153,88 +3304,88 @@ TEST_F(WebRtcIceConnectTest, TestConnect
ASSERT_TRUE_WAIT(p2_->ice_complete(), kDefaultTimeout);
AssertCheckingReached();
}
TEST_F(WebRtcIceConnectTest, TestConnectTurnTcp) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_, kNrIceTransportTcp);
ASSERT_TRUE(Gather());
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectTurnOnly) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsRelayCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
NrIceCandidate::Type::ICE_RELAYED);
Connect();
}
TEST_F(WebRtcIceConnectTest, TestConnectTurnTcpOnly) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_, kNrIceTransportTcp);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsRelayCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
NrIceCandidate::Type::ICE_RELAYED,
kNrIceTransportTcp);
Connect();
}
TEST_F(WebRtcIceConnectTest, TestSendReceiveTurnOnly) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsRelayCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
NrIceCandidate::Type::ICE_RELAYED);
Connect();
SendReceive();
}
TEST_F(WebRtcIceConnectTest, TestSendReceiveTurnTcpOnly) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
SetTurnServer(turn_server_, kDefaultStunServerPort,
turn_user_, turn_password_, kNrIceTransportTcp);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsRelayCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
NrIceCandidate::Type::ICE_RELAYED,
kNrIceTransportTcp);
Connect();
SendReceive();
}
TEST_F(WebRtcIceConnectTest, TestSendReceiveTurnBothOnly) {
if (turn_server_.empty())
return;
- AddStream("first", 1);
+ AddStream(1);
std::vector<NrIceTurnServer> turn_servers;
std::vector<unsigned char> password_vec(turn_password_.begin(),
turn_password_.end());
turn_servers.push_back(*NrIceTurnServer::Create(
turn_server_, kDefaultStunServerPort,
turn_user_, password_vec, kNrIceTransportTcp));
turn_servers.push_back(*NrIceTurnServer::Create(
turn_server_, kDefaultStunServerPort,
@@ -3246,38 +3397,38 @@ TEST_F(WebRtcIceConnectTest, TestSendRec
SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
NrIceCandidate::Type::ICE_RELAYED,
kNrIceTransportUdp);
Connect();
SendReceive();
}
TEST_F(WebRtcIceConnectTest, TestConnectShutdownOneSide) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
ConnectThenDelete();
}
TEST_F(WebRtcIceConnectTest, TestPollCandPairsBeforeConnect) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
std::vector<NrIceCandidatePair> pairs;
nsresult res = p1_->GetCandidatePairs(0, &pairs);
// There should be no candidate pairs prior to calling Connect()
ASSERT_EQ(NS_OK, res);
ASSERT_EQ(0U, pairs.size());
res = p2_->GetCandidatePairs(0, &pairs);
ASSERT_EQ(NS_OK, res);
ASSERT_EQ(0U, pairs.size());
}
TEST_F(WebRtcIceConnectTest, TestPollCandPairsAfterConnect) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
Connect();
std::vector<NrIceCandidatePair> pairs;
nsresult r = p1_->GetCandidatePairs(0, &pairs);
ASSERT_EQ(NS_OK, r);
// How detailed of a check do we want to do here? If the turn server is
// functioning, we'll get at least two pairs, but this is probably not
@@ -3293,17 +3444,17 @@ TEST_F(WebRtcIceConnectTest, TestPollCan
ASSERT_TRUE(p2_->CandidatePairsPriorityDescending(pairs));
ASSERT_TRUE(ContainsSucceededPair(pairs));
}
// TODO Bug 1259842 - disabled until we find a better way to handle two
// candidates from different RFC1918 ranges
TEST_F(WebRtcIceConnectTest, DISABLED_TestHostCandPairingFilter) {
Init(false, false, false, false);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsIpv4Candidate);
int host_net = p1_->GetCandidatesPrivateIpv4Range(0);
if (host_net <= 0) {
// TODO bug 1226838: make this work with multiple private IPs
FAIL() << "This test needs exactly one private IPv4 host candidate to work" << std::endl;
}
@@ -3327,17 +3478,17 @@ TEST_F(WebRtcIceConnectTest, DISABLED_Te
// TODO Bug 1226838 - See Comment 2 - this test can't work as written
TEST_F(WebRtcIceConnectTest, DISABLED_TestSrflxCandPairingFilter) {
if (stun_server_address_.empty()) {
return;
}
Init(false, false, false, false);
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsSrflxCandidate);
if (p1_->GetCandidatesPrivateIpv4Range(0) <= 0) {
// TODO bug 1226838: make this work with public IP addresses
std::cerr << "Don't run this test at IETF meetings!" << std::endl;
FAIL() << "This test needs one private IPv4 host candidate to work" << std::endl;
}
@@ -3365,17 +3516,17 @@ TEST_F(WebRtcIceConnectTest, DISABLED_Te
nr_str_port_to_transport_addr(p.local.local_addr.host.c_str(), 0, IPPROTO_UDP, &addr);
ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) != 0);
nr_str_port_to_transport_addr(p.remote.cand_addr.host.c_str(), 0, IPPROTO_UDP, &addr);
ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) == 0);
}
}
TEST_F(WebRtcIceConnectTest, TestPollCandPairsDuringConnect) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
p2_->Connect(p1_.get(), TRICKLE_NONE, false);
p1_->Connect(p2_.get(), TRICKLE_NONE, false);
std::vector<NrIceCandidatePair> pairs1;
std::vector<NrIceCandidatePair> pairs2;
@@ -3390,17 +3541,17 @@ TEST_F(WebRtcIceConnectTest, TestPollCan
WaitForComplete();
p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
ASSERT_TRUE(ContainsSucceededPair(pairs1));
ASSERT_TRUE(ContainsSucceededPair(pairs2));
}
TEST_F(WebRtcIceConnectTest, TestRLogRingBuffer) {
- AddStream("first", 1);
+ AddStream(1);
ASSERT_TRUE(Gather());
p2_->Connect(p1_.get(), TRICKLE_NONE, false);
p1_->Connect(p2_.get(), TRICKLE_NONE, false);
std::vector<NrIceCandidatePair> pairs1;
std::vector<NrIceCandidatePair> pairs2;
--- a/media/mtransport/test_nr_socket.cpp
+++ b/media/mtransport/test_nr_socket.cpp
@@ -79,16 +79,17 @@ nrappkit copyright:
*/
// Original author: bcampen@mozilla.com [:bwc]
extern "C" {
#include "stun_msg.h" // for NR_STUN_MAX_MESSAGE_SIZE
#include "nr_api.h"
#include "async_wait.h"
+#include "async_timer.h"
#include "nr_socket.h"
#include "nr_socket_local.h"
#include "stun_hint.h"
#include "transport_addr.h"
}
#include "mozilla/RefPtr.h"
#include "test_nr_socket.h"
@@ -194,17 +195,18 @@ int TestNat::create_socket_factory(nr_so
factorypp);
if (!r) {
AddRef();
}
return r;
}
TestNrSocket::TestNrSocket(TestNat *nat)
- : nat_(nat) {
+ : nat_(nat),
+ timer_handle_(nullptr) {
nat_->insert_socket(this);
}
TestNrSocket::~TestNrSocket() {
nat_->erase_socket(this);
}
RefPtr<NrSocketBase> TestNrSocket::create_external_socket(
@@ -247,16 +249,20 @@ int TestNrSocket::create(nr_transport_ad
return NrSocketBase::CreateSocket(addr, &internal_socket_);
}
int TestNrSocket::getaddr(nr_transport_addr *addrp) {
return internal_socket_->getaddr(addrp);
}
void TestNrSocket::close() {
+ if (timer_handle_) {
+ NR_async_timer_cancel(timer_handle_);
+ timer_handle_ = 0;
+ }
internal_socket_->close();
for (RefPtr<PortMapping>& port_mapping : port_mappings_) {
port_mapping->external_socket_->close();
}
}
int TestNrSocket::listen(int backlog) {
MOZ_ASSERT(internal_socket_->my_addr().protocol == IPPROTO_TCP);
@@ -277,21 +283,49 @@ int TestNrSocket::accept(nr_transport_ad
if (nat_->enabled_ && !nat_->is_an_internal_tuple(*addrp)) {
nr_socket_destroy(sockp);
return R_IO_ERROR;
}
return 0;
}
+void TestNrSocket::process_delayed_cb(NR_SOCKET s, int how, void *cb_arg) {
+ DeferredPacket *op = static_cast<DeferredPacket *>(cb_arg);
+ op->socket_->timer_handle_ = nullptr;
+ r_log(LOG_GENERIC, LOG_DEBUG,
+ "TestNrSocket %s sending delayed STUN response",
+ op->internal_socket_->my_addr().as_string);
+ op->internal_socket_->sendto(op->buffer_.data(), op->buffer_.len(),
+ op->flags_, &op->to_);
+
+ delete op;
+}
+
int TestNrSocket::sendto(const void *msg, size_t len,
int flags, nr_transport_addr *to) {
MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
+ UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg));
+ if (nat_->block_stun_ &&
+ nr_is_stun_message(buf, len)) {
+ return 0;
+ }
+
+ /* TODO: improve the functionality of this in bug 1253657 */
if (!nat_->enabled_ || nat_->is_an_internal_tuple(*to)) {
+ if (nat_->delay_stun_resp_ms_ &&
+ nr_is_stun_response_message(buf, len)) {
+ NR_ASYNC_TIMER_SET(nat_->delay_stun_resp_ms_,
+ process_delayed_cb,
+ new DeferredPacket(this, msg, len, flags, to,
+ internal_socket_),
+ &timer_handle_);
+ return 0;
+ }
return internal_socket_->sendto(msg, len, flags, to);
}
destroy_stale_port_mappings();
if (to->protocol == IPPROTO_UDP && nat_->block_udp_) {
// Silently eat the packet
return 0;
--- a/media/mtransport/test_nr_socket.h
+++ b/media/mtransport/test_nr_socket.h
@@ -132,16 +132,18 @@ class TestNat {
TestNat() :
enabled_(false),
filtering_type_(ENDPOINT_INDEPENDENT),
mapping_type_(ENDPOINT_INDEPENDENT),
mapping_timeout_(30000),
allow_hairpinning_(false),
refresh_on_ingress_(false),
block_udp_(false),
+ block_stun_(false),
+ delay_stun_resp_ms_(0),
sockets_() {}
bool has_port_mappings() const;
// Helps determine whether we're hairpinning
bool is_my_external_tuple(const nr_transport_addr &addr) const;
bool is_an_internal_tuple(const nr_transport_addr &addr) const;
@@ -161,16 +163,19 @@ class TestNat {
bool enabled_;
TestNat::NatBehavior filtering_type_;
TestNat::NatBehavior mapping_type_;
uint32_t mapping_timeout_;
bool allow_hairpinning_;
bool refresh_on_ingress_;
bool block_udp_;
+ bool block_stun_;
+ /* Note: this can only delay a single response so far (bug 1253657) */
+ uint32_t delay_stun_resp_ms_;
private:
std::set<TestNrSocket*> sockets_;
~TestNat(){}
};
/**
@@ -253,16 +258,36 @@ class TestNrSocket : public NrSocketBase
}
// If external_socket_ returns E_WOULDBLOCK, we don't want to propagate
// that to the code using the TestNrSocket. We can also perhaps use this
// to help simulate things like latency.
std::list<RefPtr<UdpPacket>> send_queue_;
};
+ struct DeferredPacket {
+ DeferredPacket(TestNrSocket *sock,
+ const void *data, size_t len,
+ int flags,
+ nr_transport_addr *addr,
+ RefPtr<NrSocketBase> internal_socket) :
+ socket_(sock),
+ buffer_(reinterpret_cast<const uint8_t *>(data), len),
+ flags_(flags),
+ internal_socket_(internal_socket) {
+ nr_transport_addr_copy(&to_, addr);
+ }
+
+ TestNrSocket *socket_;
+ DataBuffer buffer_;
+ int flags_;
+ nr_transport_addr to_;
+ RefPtr<NrSocketBase> internal_socket_;
+ };
+
bool is_port_mapping_stale(const PortMapping &port_mapping) const;
bool allow_ingress(const nr_transport_addr &from,
PortMapping **port_mapping_used) const;
void destroy_stale_port_mappings();
static void socket_readable_callback(void *real_sock_v,
int how,
void *test_sock_v);
@@ -283,24 +308,28 @@ class TestNrSocket : public NrSocketBase
PortMapping* get_port_mapping(const nr_transport_addr &remote_addr,
TestNat::NatBehavior filter) const;
PortMapping* create_port_mapping(
const nr_transport_addr &remote_addr,
const RefPtr<NrSocketBase> &external_socket) const;
RefPtr<NrSocketBase> create_external_socket(
const nr_transport_addr &remote_addr) const;
+ static void process_delayed_cb(NR_SOCKET s, int how, void *cb_arg);
+
RefPtr<NrSocketBase> readable_socket_;
// The socket for the "internal" address; used to talk to stuff behind the
// same nat.
RefPtr<NrSocketBase> internal_socket_;
RefPtr<TestNat> nat_;
// Since our comparison logic is different depending on what kind of NAT
// we simulate, and the STL does not make it very easy to switch out the
// comparison function at runtime, and these lists are going to be very
// small anyway, we just brute-force it.
std::list<RefPtr<PortMapping>> port_mappings_;
+
+ void *timer_handle_;
};
} // namespace mozilla
#endif // test_nr_socket__
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
@@ -120,17 +120,16 @@ int nr_ice_candidate_pair_create(nr_ice_
lcand->osock,
&rcand->addr,RTO,&pair->stun_client))
ABORT(r);
if(!(pair->stun_client->params.ice_binding_request.username=r_strdup(rcand->stream->l2r_user)))
ABORT(R_NO_MEMORY);
if(r=r_data_copy(&pair->stun_client->params.ice_binding_request.password,
&rcand->stream->l2r_pass))
ABORT(r);
- pair->stun_client->params.ice_binding_request.priority=t_priority;
/* TODO(ekr@rtfm.com): Do we need to frob this when we change role. Bug 890667 */
pair->stun_client->params.ice_binding_request.control = pctx->controlling?
NR_ICE_CONTROLLING:NR_ICE_CONTROLLED;
pair->stun_client->params.ice_binding_request.priority=t_priority;
pair->stun_client->params.ice_binding_request.tiebreaker=pctx->tiebreaker;
*pairp=pair;
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -44,19 +44,22 @@ static char *RCSSTRING __UNUSED__="$Id:
#include "stun.h"
#include "nr_socket_local.h"
#include "nr_socket_turn.h"
#include "nr_socket_wrapper.h"
#include "nr_socket_buffered_stun.h"
#include "nr_socket_multi_tcp.h"
#include "ice_reg.h"
#include "nr_crypto.h"
+#include "r_time.h"
static int nr_ice_component_stun_server_default_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error);
static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp);
+void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp);
+void nr_ice_component_consent_destroy(nr_ice_component *comp);
/* This function takes ownership of the contents of req (but not req itself) */
static int nr_ice_pre_answer_request_create(nr_socket *sock, nr_stun_server_request *req, nr_ice_pre_answer_request **parp)
{
int r, _status;
nr_ice_pre_answer_request *par = 0;
nr_stun_message_attribute *attr;
@@ -136,16 +139,18 @@ int nr_ice_component_destroy(nr_ice_comp
nr_ice_pre_answer_request *r1,*r2;
if(!componentp || !*componentp)
return(0);
component=*componentp;
*componentp=0;
+ nr_ice_component_consent_destroy(component);
+
/* Detach ourselves from the sockets */
if (component->local_component){
nr_ice_socket *isock=STAILQ_FIRST(&component->local_component->sockets);
while(isock){
nr_stun_server_remove_client(isock->stun_server, component);
isock=STAILQ_NEXT(isock, entry);
}
}
@@ -162,20 +167,16 @@ int nr_ice_component_destroy(nr_ice_comp
nr_ice_socket_destroy(&s1);
}
STAILQ_FOREACH_SAFE(r1, &component->pre_answer_reqs, entry, r2){
STAILQ_REMOVE(&component->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry);
nr_ice_pre_answer_request_destroy(&r1);
}
- if(component->keepalive_timer)
- NR_async_timer_cancel(component->keepalive_timer);
- nr_stun_client_ctx_destroy(&component->keepalive_ctx);
-
RFREE(component);
return(0);
}
static int nr_ice_component_create_stun_server_ctx(nr_ice_component *component, nr_ice_socket *isock, nr_socket *sock, nr_transport_addr *addr, char *lufrag, Data *pwd)
{
char label[256];
int r,_status;
@@ -1149,26 +1150,224 @@ static int nr_ice_component_stun_server_
*dont_free = 1;
STAILQ_INSERT_TAIL(&comp->pre_answer_reqs, par, entry);
_status=0;
abort:
return(_status);
}
+#define NR_ICE_CONSENT_TIMER_DEFAULT 5000
+#define NR_ICE_CONSENT_TIMEOUT_DEFAULT 30000
+
+static void nr_ice_component_consent_failed(nr_ice_component *comp)
+ {
+ if (!comp->can_send) {
+ return;
+ }
+
+ r_log(LOG_ICE,LOG_INFO,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh failed",
+ comp->ctx->label, comp->stream->label, comp->component_id);
+ comp->can_send = 0;
+
+ if (comp->consent_timeout) {
+ NR_async_timer_cancel(comp->consent_timeout);
+ comp->consent_timeout = 0;
+ }
+ if (comp->consent_timer) {
+ NR_async_timer_cancel(comp->consent_timer);
+ comp->consent_timer = 0;
+ }
+ /* We are turning the consent failure into a ICE component failure to
+ * alert the browser via ICE connection state change about this event. */
+ if (nr_ice_media_stream_component_failed(comp->stream, comp))
+ r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): failed to mark component as failed",
+ comp->ctx->label, comp->stream->label, comp->component_id);
+ }
+
+static void nr_ice_component_consent_timeout_cb(NR_SOCKET s, int how, void *cb_arg)
+ {
+ nr_ice_component *comp=cb_arg;
+
+ comp->consent_timeout = 0;
+
+ r_log(LOG_ICE,LOG_WARNING,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh timed out",
+ comp->ctx->label, comp->stream->label, comp->component_id);
+ nr_ice_component_consent_failed(comp);
+ }
+
+static void nr_ice_component_consent_refreshed(nr_ice_component *comp)
+ {
+ uint16_t tval;
+
+ if (!comp->can_send) {
+ return;
+ }
+
+ gettimeofday(&comp->consent_last_seen, 0);
+ r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): consent_last_seen is now %lu",
+ comp->ctx->label, comp->stream->label, comp->component_id,
+ comp->consent_last_seen.tv_sec);
+ if (comp->consent_timeout)
+ NR_async_timer_cancel(comp->consent_timeout);
+
+ tval = NR_ICE_CONSENT_TIMEOUT_DEFAULT;
+ if (comp->ctx->test_timer_divider)
+ tval = tval / comp->ctx->test_timer_divider;
+
+ NR_ASYNC_TIMER_SET(tval, nr_ice_component_consent_timeout_cb, comp,
+ &comp->consent_timeout);
+ }
+
+static void nr_ice_component_refresh_consent_cb(NR_SOCKET s, int how, void *cb_arg)
+ {
+ nr_ice_component *comp=cb_arg;
+
+ switch (comp->consent_ctx->state) {
+ case NR_STUN_CLIENT_STATE_FAILED:
+ if (comp->consent_ctx->error_code == 403) {
+ r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): Consent revoked by peer",
+ comp->ctx->label, comp->stream->label, comp->component_id);
+ nr_ice_component_consent_failed(comp);
+ }
+ break;
+ case NR_STUN_CLIENT_STATE_DONE:
+ r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): Consent refreshed",
+ comp->ctx->label, comp->stream->label, comp->component_id);
+ nr_ice_component_consent_refreshed(comp);
+ break;
+ default:
+ break;
+ }
+ }
+
+int nr_ice_component_refresh_consent(nr_stun_client_ctx *ctx, NR_async_cb finished_cb, void *cb_arg)
+ {
+ int r,_status;
+
+ nr_stun_client_reset(ctx);
+
+ if (r=nr_stun_client_start(ctx, NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH, finished_cb, cb_arg))
+ ABORT(r);
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
+static void nr_ice_component_consent_timer_cb(NR_SOCKET s, int how, void *cb_arg)
+ {
+ nr_ice_component *comp=cb_arg;
+ int r;
+
+ comp->consent_timer = 0;
+
+ if (r=nr_ice_component_refresh_consent(comp->consent_ctx,
+ nr_ice_component_refresh_consent_cb,
+ comp)) {
+ r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): Refresh consent failed with %d",
+ comp->ctx->label, comp->stream->label, comp->component_id, r);
+ /* In case our attempt to send the refresh binding request reports an
+ * error we don't have to wait for timeouts, but declare this connection
+ * dead right away. */
+ if (r != R_WOULDBLOCK) {
+ nr_ice_component_consent_failed(comp);
+ }
+ }
+
+ nr_ice_component_consent_schedule_consent_timer(comp);
+
+ }
+
+void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp)
+ {
+ uint16_t trange, trand, tval;
+ void *buf = &trand;
+
+ trange = NR_ICE_CONSENT_TIMER_DEFAULT / 100 * 20;
+ tval = NR_ICE_CONSENT_TIMER_DEFAULT - trange;
+ if (!nr_crypto_random_bytes(buf, sizeof(trand)))
+ tval += (trand % (trange * 2));
+
+ if (comp->ctx->test_timer_divider)
+ tval = tval / comp->ctx->test_timer_divider;
+
+ NR_ASYNC_TIMER_SET(tval, nr_ice_component_consent_timer_cb, comp,
+ &comp->consent_timer);
+ }
+
+void nr_ice_component_consent_destroy(nr_ice_component *comp)
+ {
+ if (comp->consent_timer) {
+ NR_async_timer_cancel(comp->consent_timer);
+ comp->consent_timer = 0;
+ }
+ if (comp->consent_timeout) {
+ NR_async_timer_cancel(comp->consent_timeout);
+ comp->consent_timeout = 0;
+ }
+ if (comp->consent_handle) {
+ nr_ice_socket_deregister(comp->active->local->isock,
+ comp->consent_handle);
+ comp->consent_handle = 0;
+ }
+ if (comp->consent_ctx) {
+ nr_stun_client_ctx_destroy(&comp->consent_ctx);
+ }
+ }
+
+int nr_ice_component_setup_consent(nr_ice_component *comp)
+ {
+ int r,_status;
+
+ r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Setting up refresh consent",
+ comp->ctx->label, comp->stream->label, comp->component_id);
+
+ if (r=nr_stun_client_ctx_create("consent", comp->active->local->osock,
+ &comp->active->remote->addr, 0,
+ &comp->consent_ctx))
+ ABORT(r);
+ /* Consent request get send only once. */
+ comp->consent_ctx->maximum_transmits = 1;
+ /* The timeout of the transaction is the maximum time until we send the
+ * next consent request.
+ * TODO: set this every time we calculate the new random timeout. */
+ comp->consent_ctx->maximum_transmits_timeout_ms = 6000;
+ comp->consent_ctx->params.stun_binding_request.username =
+ comp->active->remote->stream->l2r_user;
+ comp->consent_ctx->params.stun_binding_request.password =
+ &comp->active->remote->stream->l2r_pass;
+
+ if (r=nr_ice_socket_register_stun_client(comp->active->local->isock,
+ comp->consent_ctx, &comp->consent_handle))
+ ABORT(r);
+
+ comp->can_send = 1;
+ nr_ice_component_consent_refreshed(comp);
+
+ nr_ice_component_consent_schedule_consent_timer(comp);
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
{
int r,_status;
nr_ice_cand_pair *p2;
/* Are we changing what the nominated pair is? */
if(comp->nominated){
if(comp->nominated->priority >= pair->priority)
return(0);
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): replacing pair %s with CAND-PAIR(%s)",comp->stream->pctx->label,comp->stream->label,comp->component_id,comp->nominated->codeword,comp->nominated->as_string,pair->codeword);
+ /* As consent doesn't hold a reference to its isock this needs to happen
+ * before making the new pair the active one. */
+ nr_ice_component_consent_destroy(comp);
}
/* Set the new nominated pair */
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): nominated pair is %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->codeword,pair->as_string);
comp->state=NR_ICE_COMPONENT_NOMINATED;
comp->nominated=pair;
comp->active=pair;
@@ -1200,16 +1399,19 @@ int nr_ice_component_nominated_pair(nr_i
if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2,0))
ABORT(r);
}
p2=TAILQ_NEXT(p2,check_queue_entry);
}
r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): cancelling done",comp->stream->pctx->label,comp->stream->label,comp->component_id);
+ if(r=nr_ice_component_setup_consent(comp))
+ ABORT(r);
+
if(r=nr_ice_media_stream_component_nominated(comp->stream,comp))
ABORT(r);
_status=0;
abort:
return(_status);
}
@@ -1300,67 +1502,35 @@ int nr_ice_component_select_pair(nr_ice_
_status=0;
abort:
RFREE(pairs);
return(_status);
}
-static void nr_ice_component_keepalive_cb(NR_SOCKET s, int how, void *cb_arg)
- {
- nr_ice_component *comp=cb_arg;
- UINT4 keepalive_timeout;
-
- assert(comp->keepalive_ctx);
-
- if(NR_reg_get_uint4(NR_ICE_REG_KEEPALIVE_TIMER,&keepalive_timeout)){
- keepalive_timeout=15000; /* Default */
- }
-
- if(comp->keepalive_needed)
- nr_stun_client_force_retransmit(comp->keepalive_ctx);
-
- comp->keepalive_needed=1;
- NR_ASYNC_TIMER_SET(keepalive_timeout,nr_ice_component_keepalive_cb,cb_arg,&comp->keepalive_timer);
- }
-
-
/* Close the underlying sockets for everything but the nominated candidate */
int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp)
{
nr_ice_socket *isock=0;
- int r,_status;
nr_ice_socket *s1,*s2;
if(rcomp->state==NR_ICE_COMPONENT_NOMINATED){
assert(rcomp->active == rcomp->nominated);
isock=rcomp->nominated->local->isock;
}
STAILQ_FOREACH_SAFE(s1, &lcomp->sockets, entry, s2){
if(s1!=isock){
STAILQ_REMOVE(&lcomp->sockets,s1,nr_ice_socket_,entry);
nr_ice_socket_destroy(&s1);
}
}
- /* Set up the keepalives for the chosen socket */
- if(r=nr_stun_client_ctx_create("keepalive",rcomp->nominated->local->osock,
- &rcomp->nominated->remote->addr,0,&rcomp->keepalive_ctx))
- ABORT(r);
- if(r=nr_stun_client_start(rcomp->keepalive_ctx,NR_STUN_CLIENT_MODE_KEEPALIVE,0,0))
- ABORT(r);
- nr_ice_component_keepalive_cb(0,0,rcomp);
-
-
- _status=0;
- abort:
-
- return(_status);
+ return(0);
}
int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair)
{
int r,_status;
/* Pairs for peer reflexive are marked SUCCEEDED immediately */
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.h
@@ -65,19 +65,22 @@ struct nr_ice_component_ {
nr_ice_candidate_head candidates;
int candidate_ct;
nr_ice_pre_answer_request_head pre_answer_reqs;
int valid_pairs;
struct nr_ice_cand_pair_ *nominated; /* Highest priority nomninated pair */
struct nr_ice_cand_pair_ *active;
- int keepalive_needed;
- void *keepalive_timer;
- nr_stun_client_ctx *keepalive_ctx;
+ nr_stun_client_ctx *consent_ctx;
+ void *consent_timer;
+ void *consent_timeout;
+ void *consent_handle;
+ int can_send;
+ struct timeval consent_last_seen;
STAILQ_ENTRY(nr_ice_component_)entry;
};
typedef STAILQ_HEAD(nr_ice_component_head_,nr_ice_component_) nr_ice_component_head;
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);
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
@@ -408,16 +408,18 @@ int nr_ice_ctx_create_with_credentials(c
ABORT(r);
}
}
#endif /* USE_TURN */
ctx->Ta = 20;
+ ctx->test_timer_divider = 0;
+
if (r=nr_socket_factory_create_int(NULL, &default_socket_factory_vtbl, &ctx->socket_factory))
ABORT(r);
if ((r=NR_reg_get_string((char *)NR_ICE_REG_PREF_FORCE_INTERFACE_NAME, ctx->force_net_interface, sizeof(ctx->force_net_interface)))) {
if (r == R_NOT_FOUND) {
ctx->force_net_interface[0] = 0;
} else {
ABORT(r);
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
@@ -137,16 +137,18 @@ struct nr_ice_ctx_ {
nr_ice_media_stream_head streams; /* Media streams */
int stream_ct;
nr_ice_socket_head sockets; /* The sockets we're using */
int uninitialized_candidates;
UINT4 gather_rto;
UINT4 stun_delay;
+ UINT4 test_timer_divider;
+
nr_ice_peer_ctx_head peers;
nr_ice_stun_id_head ids;
NR_async_cb done_cb;
void *cb_arg;
nr_ice_trickle_candidate_cb trickle_cb;
void *trickle_cb_arg;
--- a/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
@@ -733,21 +733,24 @@ int nr_ice_media_stream_send(nr_ice_peer
/* First find the peer component */
if(r=nr_ice_peer_ctx_find_component(pctx, str, component, &comp))
ABORT(r);
/* Do we have an active pair yet? We should... */
if(!comp->active)
ABORT(R_NOT_FOUND);
+ /* Does fresh ICE consent exist? */
+ if(!comp->can_send)
+ ABORT(R_FAILED);
+
/* OK, write to that pair, which means:
1. Use the socket on our local side.
2. Use the address on the remote side
*/
- comp->keepalive_needed=0; /* Suppress keepalives */
if(r=nr_socket_sendto(comp->active->local->osock,data,len,0,
&comp->active->remote->addr))
ABORT(r);
_status=0;
abort:
return(_status);
}
@@ -841,16 +844,33 @@ int nr_ice_media_stream_pair_new_trickle
if (r=nr_ice_component_pair_candidate(pctx, comp, cand, 1))
ABORT(r);
_status=0;
abort:
return(_status);
}
+int nr_ice_media_stream_get_consent_status(nr_ice_media_stream *stream, int
+component_id, int *can_send, struct timeval *ts)
+ {
+ int r,_status;
+ nr_ice_component *comp;
+
+ if ((r=nr_ice_media_stream_find_component(stream, component_id, &comp)))
+ ABORT(r);
+
+ *can_send = comp->can_send;
+ ts->tv_sec = comp->consent_last_seen.tv_sec;
+ ts->tv_usec = comp->consent_last_seen.tv_usec;
+ _status=0;
+ abort:
+ return(_status);
+ }
+
int nr_ice_media_stream_disable_component(nr_ice_media_stream *stream, int component_id)
{
int r,_status;
nr_ice_component *comp;
if (stream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED)
ABORT(R_FAILED);
--- a/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.h
@@ -90,16 +90,17 @@ int nr_ice_media_stream_component_failed
int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state);
int nr_ice_media_stream_get_best_candidate(nr_ice_media_stream *str, int component, nr_ice_candidate **candp);
int nr_ice_media_stream_send(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, UCHAR *data, int len);
int nr_ice_media_stream_get_active(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, nr_ice_candidate **local, nr_ice_candidate **remote);
int nr_ice_media_stream_find_component(nr_ice_media_stream *str, int comp_id, nr_ice_component **compp);
int nr_ice_media_stream_addrs(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, nr_transport_addr *local, nr_transport_addr *remote);
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_get_consent_status(nr_ice_media_stream *stream, int component_id, int *can_send, struct timeval *ts);
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);
void nr_ice_media_stream_role_change(nr_ice_media_stream *stream);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.c
@@ -50,17 +50,17 @@ static char *RCSSTRING __UNUSED__="$Id:
#endif
#include <assert.h>
#include "nr_api.h"
#include "transport_addr.h"
int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr)
{
int _status;
- /* Max length for normalized IPv6 address string represntation is 39 */
+ /* Max length for normalized IPv6 address string representation is 39 */
char buffer[40];
const char *protocol;
switch(addr->protocol){
case IPPROTO_TCP:
protocol = "TCP";
break;
case IPPROTO_UDP:
@@ -464,9 +464,12 @@ int nr_transport_addr_get_private_addr_r
return(0);
default:
UNIMPLEMENTED;
}
return(0);
}
-
+int nr_transport_addr_is_reliable_transport(nr_transport_addr *addr)
+ {
+ return addr->protocol == IPPROTO_TCP;
+ }
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.h
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.h
@@ -92,11 +92,12 @@ int nr_transport_addr_is_wildcard(nr_tra
int nr_transport_addr_is_loopback(nr_transport_addr *addr);
int nr_transport_addr_get_private_addr_range(nr_transport_addr *addr);
int nr_transport_addr_is_link_local(nr_transport_addr *addr);
int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from);
int nr_transport_addr_copy_keep_ifname(nr_transport_addr *to, nr_transport_addr *from);
int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr);
int nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr *addr, char *buf, int len);
int nr_transport_addr_set_port(nr_transport_addr *addr, int port);
+int nr_transport_addr_is_reliable_transport(nr_transport_addr *addr);
#endif