Bug 1187775 - skip host and reflexive ICE candidates if relay-only. r=bwc

This commit is contained in:
Jan-Ivar Bruaroey 2015-08-05 08:22:55 -04:00
parent fc835152ee
commit fd310e2cd0
8 changed files with 138 additions and 47 deletions

View File

@ -118,6 +118,8 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_promiseSendOnly.html] [test_peerConnection_promiseSendOnly.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_relayOnly.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_callbacks.html] [test_peerConnection_callbacks.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_replaceTrack.html] [test_peerConnection_replaceTrack.html]

View File

@ -1189,18 +1189,15 @@ PeerConnectionWrapper.prototype = {
* resolves when connected, rejects on failure * resolves when connected, rejects on failure
*/ */
waitForIceConnected : function() { waitForIceConnected : function() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) =>
var iceConnectedChanged = () => { this.ice_connection_callbacks.waitForIceConnected = () => {
if (this.isIceConnected()) { if (this.isIceConnected()) {
delete this.ice_connection_callbacks.waitForIceConnected; delete this.ice_connection_callbacks.waitForIceConnected;
resolve(); resolve();
} else if (! this.isIceConnectionPending()) { } else if (!this.isIceConnectionPending()) {
delete this.ice_connection_callbacks.waitForIceConnected; delete this.ice_connection_callbacks.waitForIceConnected;
resolve(); reject(new Error('ICE failed'));
}
} }
this.ice_connection_callbacks.waitForIceConnected = iceConnectedChanged;
}); });
}, },

View File

@ -0,0 +1,61 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "1187775",
title: "peer connection ICE fails on relay-only without TURN"
});
function PC_LOCAL_NO_CANDIDATES(test) {
var isnt = can => is(can, null, "No candidates: " + JSON.stringify(can));
test.pcLocal._pc.addEventListener("icecandidate", e => isnt(e.candidate));
}
function PC_BOTH_WAIT_FOR_ICE_FAILED(test) {
var isFail = (f, reason, msg) =>
f().then(() => { throw new Error(msg + " must fail"); },
e => is(e.message, reason, msg + " must fail with: " + e.message));
return Promise.all([
isFail(() => waitForIceConnected(test, test.pcLocal), "ICE failed", "Local ICE"),
isFail(() => waitForIceConnected(test, test.pcRemote), "ICE failed", "Remote ICE")
])
.then(() => ok(true, "ICE on both sides must fail."));
}
var pushPrefs = (...p) => new Promise(r => SpecialPowers.pushPrefEnv({set: p}, r));
var test;
runNetworkTest(options =>
pushPrefs(['media.peerconnection.ice.stun_client_maximum_transmits', 3],
['media.peerconnection.ice.trickle_grace_period', 5000]).then(() => {
options = options || {};
options.config_local = options.config_local || {};
var servers = options.config_local.iceServers || [];
// remove any turn servers
options.config_local.iceServers = servers.filter(server =>
server.urls.every(u => !u.toLowerCase().startsWith('turn')));
// Here's the setting we're testing. Comment out and this test should fail:
options.config_local.iceTransportPolicy = "relay";
test = new PeerConnectionTest(options);
test.setMediaConstraints([{audio: true}, {video: true}],
[{audio: true}, {video: true}]);
test.chain.remove("PC_LOCAL_SETUP_ICE_LOGGER"); // Needed to suppress failing
test.chain.remove("PC_REMOTE_SETUP_ICE_LOGGER"); // on ICE-failure.
test.chain.insertAfter("PC_LOCAL_SETUP_ICE_HANDLER", PC_LOCAL_NO_CANDIDATES);
test.chain.replace("PC_LOCAL_WAIT_FOR_ICE_CONNECTED", PC_BOTH_WAIT_FOR_ICE_FAILED);
test.chain.removeAfter("PC_BOTH_WAIT_FOR_ICE_FAILED");
test.run();
}));
</script>
</pre>
</body>
</html>

View File

@ -486,6 +486,9 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER: UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER:
NR_ICE_CTX_FLAGS_ANSWERER; NR_ICE_CTX_FLAGS_ANSWERER;
flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION; flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
if (policy == ICE_POLICY_RELAY) {
flags |= NR_ICE_CTX_FLAGS_RELAY_ONLY;
}
r = nr_ice_ctx_create(const_cast<char *>(name.c_str()), flags, r = nr_ice_ctx_create(const_cast<char *>(name.c_str()), flags,
&ctx->ctx_); &ctx->ctx_);
@ -720,6 +723,9 @@ abort:
nsresult NrIceCtx::StartGathering() { nsresult NrIceCtx::StartGathering() {
ASSERT_ON_THREAD(sts_target_); ASSERT_ON_THREAD(sts_target_);
if (policy_ == ICE_POLICY_NONE) {
return NS_OK;
}
SetGatheringState(ICE_CTX_GATHER_STARTED); SetGatheringState(ICE_CTX_GATHER_STARTED);
// This might start gathering for the first time, or again after // This might start gathering for the first time, or again after
// renegotiation, or might do nothing at all if gathering has already // renegotiation, or might do nothing at all if gathering has already
@ -794,6 +800,11 @@ nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) {
nsresult NrIceCtx::StartChecks() { nsresult NrIceCtx::StartChecks() {
int r; int r;
if (policy_ == ICE_POLICY_NONE) {
MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks because policy == none");
SetConnectionState(ICE_CTX_FAILED);
return NS_ERROR_FAILURE;
}
r=nr_ice_peer_ctx_pair_candidates(peer_); r=nr_ice_peer_ctx_pair_candidates(peer_);
if (r) { if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't pair candidates on " MOZ_MTLOG(ML_ERROR, "Couldn't pair candidates on "

View File

@ -134,6 +134,7 @@ static int nr_ice_candidate_format_stun_label(char *label, size_t size, nr_ice_c
int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_socket_tcp_type tcp_type, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp) int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_socket_tcp_type tcp_type, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp)
{ {
assert(!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) || ctype == RELAYED);
nr_ice_candidate *cand=0; nr_ice_candidate *cand=0;
nr_ice_candidate *tmp=0; nr_ice_candidate *tmp=0;
int r,_status; int r,_status;
@ -921,6 +922,7 @@ int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int ma
char addr[64]; char addr[64];
int port; int port;
int len; int len;
nr_transport_addr *raddr;
assert(!strcmp(nr_ice_candidate_type_names[HOST], "host")); assert(!strcmp(nr_ice_candidate_type_names[HOST], "host"));
assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay")); assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay"));
@ -939,23 +941,26 @@ int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int ma
len=strlen(attr); attr+=len; maxlen-=len; len=strlen(attr); attr+=len; maxlen-=len;
/* raddr, rport */ /* raddr, rport */
raddr = (cand->stream->ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) ?
&cand->addr : &cand->base;
switch(cand->type){ switch(cand->type){
case HOST: case HOST:
break; break;
case SERVER_REFLEXIVE: case SERVER_REFLEXIVE:
case PEER_REFLEXIVE: case PEER_REFLEXIVE:
if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr))) if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
ABORT(r); ABORT(r);
if(r=nr_transport_addr_get_port(&cand->base,&port)) if(r=nr_transport_addr_get_port(raddr,&port))
ABORT(r); ABORT(r);
snprintf(attr,maxlen," raddr %s rport %d",addr,port); snprintf(attr,maxlen," raddr %s rport %d",addr,port);
break; break;
case RELAYED: case RELAYED:
// comes from XorMappedAddress via AllocateResponse // comes from XorMappedAddress via AllocateResponse
if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr))) if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
ABORT(r); ABORT(r);
if(r=nr_transport_addr_get_port(&cand->base,&port)) if(r=nr_transport_addr_get_port(raddr,&port))
ABORT(r); ABORT(r);
snprintf(attr,maxlen," raddr %s rport %d",addr,port); snprintf(attr,maxlen," raddr %s rport %d",addr,port);

View File

@ -260,7 +260,12 @@ static void nr_ice_candidate_pair_stun_cb(NR_SOCKET s, int how, void *cb_arg)
} }
/* OK, nothing found, must be peer reflexive */ /* OK, nothing found, must be peer reflexive */
if(!cand){ if(!cand) {
if (pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) {
/* Any STUN response with a reflexive address in it is unwanted
when we'll send on relay only. Bail since cand is used below. */
goto done;
}
if(r=nr_ice_candidate_create(pair->pctx->ctx, if(r=nr_ice_candidate_create(pair->pctx->ctx,
pair->local->component,pair->local->isock,pair->local->osock, pair->local->component,pair->local->isock,pair->local->osock,
PEER_REFLEXIVE,pair->local->tcp_type,0,pair->local->component->component_id,&cand)) PEER_REFLEXIVE,pair->local->tcp_type,0,pair->local->component->component_id,&cand))

View File

@ -226,53 +226,59 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
if(r=nr_ice_socket_create(ctx,component,sock,NR_ICE_SOCKET_TYPE_DGRAM,&isock)) if(r=nr_ice_socket_create(ctx,component,sock,NR_ICE_SOCKET_TYPE_DGRAM,&isock))
ABORT(r); ABORT(r);
/* Create one host candidate */
if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,0,
component->component_id,&cand))
ABORT(r);
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp); if (!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY)) {
component->candidate_ct++; /* Create one host candidate */
cand=0; if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,0,
component->component_id,&cand))
/* And a srvrflx candidate for each STUN server */
for(j=0;j<ctx->stun_server_ct;j++){
/* Skip non-UDP */
if(ctx->stun_servers[j].transport!=IPPROTO_UDP)
continue;
if(r=nr_ice_candidate_create(ctx,component,
isock,sock,SERVER_REFLEXIVE,0,
&ctx->stun_servers[j],component->component_id,&cand))
ABORT(r); ABORT(r);
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp); TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
component->candidate_ct++; component->candidate_ct++;
cand=0; cand=0;
/* And a srvrflx candidate for each STUN server */
for(j=0;j<ctx->stun_server_ct;j++){
/* Skip non-UDP */
if(ctx->stun_servers[j].transport!=IPPROTO_UDP)
continue;
if(r=nr_ice_candidate_create(ctx,component,
isock,sock,SERVER_REFLEXIVE,0,
&ctx->stun_servers[j],component->component_id,&cand))
ABORT(r);
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
component->candidate_ct++;
cand=0;
}
} }
#ifdef USE_TURN #ifdef USE_TURN
/* And both a srvrflx and relayed candidate for each TURN server */ /* And both a srvrflx and relayed candidate for each TURN server (unless
we're in relay-only mode, in which case just the relayed one) */
for(j=0;j<ctx->turn_server_ct;j++){ for(j=0;j<ctx->turn_server_ct;j++){
nr_socket *turn_sock; nr_socket *turn_sock;
nr_ice_candidate *srvflx_cand; nr_ice_candidate *srvflx_cand=0;
/* Skip non-UDP */ /* Skip non-UDP */
if (ctx->turn_servers[j].turn_server.transport != IPPROTO_UDP) if (ctx->turn_servers[j].turn_server.transport != IPPROTO_UDP)
continue; continue;
/* srvrflx */ if (!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY)) {
if(r=nr_ice_candidate_create(ctx,component, /* srvrflx */
isock,sock,SERVER_REFLEXIVE,0, if(r=nr_ice_candidate_create(ctx,component,
&ctx->turn_servers[j].turn_server,component->component_id,&cand)) isock,sock,SERVER_REFLEXIVE,0,
ABORT(r); &ctx->turn_servers[j].turn_server,component->component_id,&cand))
cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */ ABORT(r);
cand->done_cb=nr_ice_gather_finished_cb; cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
cand->cb_arg=cand; cand->done_cb=nr_ice_gather_finished_cb;
cand->cb_arg=cand;
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
component->candidate_ct++;
srvflx_cand=cand;
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
component->candidate_ct++;
srvflx_cand=cand;
cand=0;
}
/* relayed*/ /* relayed*/
if(r=nr_socket_turn_create(sock, &turn_sock)) if(r=nr_socket_turn_create(sock, &turn_sock))
ABORT(r); ABORT(r);
@ -408,6 +414,9 @@ static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_compon
if (r != R_NOT_FOUND) if (r != R_NOT_FOUND)
ABORT(r); ABORT(r);
} }
if (ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) {
ice_tcp_disabled = 1;
}
for(i=0;i<addr_ct;i++){ for(i=0;i<addr_ct;i++){
char suppress; char suppress;

View File

@ -157,6 +157,7 @@ int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp);
#define NR_ICE_CTX_FLAGS_ANSWERER (1<<1) #define NR_ICE_CTX_FLAGS_ANSWERER (1<<1)
#define NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION (1<<2) #define NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION (1<<2)
#define NR_ICE_CTX_FLAGS_LITE (1<<3) #define NR_ICE_CTX_FLAGS_LITE (1<<3)
#define NR_ICE_CTX_FLAGS_RELAY_ONLY (1<<4)
int nr_ice_ctx_destroy(nr_ice_ctx **ctxp); int nr_ice_ctx_destroy(nr_ice_ctx **ctxp);
int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg); int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg);