test_peerConnection_gatherWithSetConfiguration.html (21224B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <script type="application/javascript" src="pc.js"></script> 5 <script type="application/javascript" src="iceTestUtils.js"></script> 6 <script type="application/javascript" src="helpers_from_wpt/sdp.js"></script></head> 7 <body> 8 <pre id="test"> 9 <script type="application/javascript"> 10 createHTML({ 11 bug: "1253706", 12 title: "Test ICE gathering when setConfiguration is used to change the ICE config" 13 }); 14 15 const tests = [ 16 async function baselineV4Cases() { 17 await checkSrflx([{urls:[`stun:${turnAddressV4}`]}]); 18 await checkRelayUdp([{urls:[`turn:${turnAddressV4}`], username, credential}]); 19 await checkRelayTcp([{urls:[`turn:${turnAddressV4}?transport=tcp`], username, credential}]); 20 await checkRelayUdpTcp([{urls:[`turn:${turnAddressV4}`, `turn:${turnAddressV4}?transport=tcp`], username, credential}]); 21 await checkNoSrflx(); 22 await checkNoRelay(); 23 }, 24 25 async function addStunServerBeforeOffer() { 26 const pc = new RTCPeerConnection(); 27 try { 28 pc.setConfiguration({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 29 const candidates = await gatherWithTimeout(pc, 32000, `just a stun server`); 30 ok(candidates.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 31 ok(!candidates.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 32 } finally { 33 pc.close(); 34 } 35 }, 36 37 async function addTurnServerBeforeOffer() { 38 const pc = new RTCPeerConnection(); 39 try { 40 pc.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}`], username, credential}]}); 41 const candidates = await gatherWithTimeout(pc, 32000, `a turn (udp) server`); 42 ok(candidates.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 43 ok(candidates.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 44 } finally { 45 pc.close(); 46 } 47 }, 48 49 async function addTurnTcpServerBeforeOffer() { 50 const pc = new RTCPeerConnection(); 51 try { 52 pc.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}?transport=tcp`], username, credential}]}); 53 const candidates = await gatherWithTimeout(pc, 32000, `a turn (tcp) server`); 54 ok(!candidates.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 55 ok(candidates.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 56 } finally { 57 pc.close(); 58 } 59 }, 60 61 async function addStunServerAfterOffer() { 62 const pc = new RTCPeerConnection(); 63 try { 64 const candidates1 = await gatherWithTimeout(pc, 32000, `no ICE servers`); 65 ok(!candidates1.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 66 ok(!candidates1.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 67 await pc.setLocalDescription({type: "rollback"}); 68 69 pc.setConfiguration({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 70 const candidates2 = await gatherWithTimeout(pc, 32000, `just a stun server`); 71 ok(candidates2.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 72 ok(!candidates2.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 73 } finally { 74 pc.close(); 75 } 76 }, 77 78 async function addTurnServerAfterOffer() { 79 const pc = new RTCPeerConnection(); 80 try { 81 const candidates1 = await gatherWithTimeout(pc, 32000, `no ICE servers`); 82 ok(!candidates1.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 83 ok(!candidates1.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 84 await pc.setLocalDescription({type: "rollback"}); 85 86 pc.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}`], username, credential}]}); 87 const candidates2 = await gatherWithTimeout(pc, 32000, `a turn (udp) server`); 88 ok(candidates2.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 89 ok(candidates2.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 90 } finally { 91 pc.close(); 92 } 93 }, 94 95 async function addTurnTcpServerAfterOffer() { 96 const pc = new RTCPeerConnection(); 97 try { 98 const candidates1 = await gatherWithTimeout(pc, 32000, `no ICE servers`); 99 ok(!candidates1.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 100 ok(!candidates1.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 101 await pc.setLocalDescription({type: "rollback"}); 102 103 pc.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}?transport=tcp`], username, credential}]}); 104 const candidates2 = await gatherWithTimeout(pc, 32000, `a turn (tcp) server`); 105 ok(!candidates2.some(c => c.candidate.includes("srflx")), "Should get no srflx candidates"); 106 ok(candidates2.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 107 } finally { 108 pc.close(); 109 } 110 }, 111 112 async function removeStunServerBeforeOffer() { 113 const pc = new RTCPeerConnection({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 114 try { 115 pc.setConfiguration({}); 116 const candidates = await gatherWithTimeout(pc, 32000, `no ICE servers`); 117 ok(!candidates.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 118 ok(!candidates.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 119 } finally { 120 pc.close(); 121 } 122 }, 123 124 async function removeTurnServerBeforeOffer() { 125 const pc = new RTCPeerConnection({iceServers: [{urls:[`turn:${turnAddressV4}`], username, credential}]}); 126 try { 127 pc.setConfiguration({}); 128 const candidates = await gatherWithTimeout(pc, 32000, `no ICE servers`); 129 ok(!candidates.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 130 ok(!candidates.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 131 } finally { 132 pc.close(); 133 } 134 }, 135 136 async function removeTurnTcpServerBeforeOffer() { 137 const pc = new RTCPeerConnection({iceServers: [{urls:[`turn:${turnAddressV4}?transport=tcp`], username, credential}]}); 138 try { 139 pc.setConfiguration({}); 140 const candidates = await gatherWithTimeout(pc, 32000, `no ICE servers`); 141 ok(!candidates.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 142 ok(!candidates.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 143 } finally { 144 pc.close(); 145 } 146 }, 147 148 async function removeStunServerAfterOffer() { 149 const pc = new RTCPeerConnection({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 150 try { 151 const candidates1 = await gatherWithTimeout(pc, 32000, `just a stun server`); 152 ok(candidates1.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 153 ok(!candidates1.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 154 await pc.setLocalDescription({type: "rollback"}); 155 156 pc.setConfiguration({}); 157 const candidates2 = await gatherWithTimeout(pc, 32000, `no ICE servers`); 158 ok(!candidates2.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 159 ok(!candidates2.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 160 } finally { 161 pc.close(); 162 } 163 }, 164 165 async function removeTurnServerAfterOffer() { 166 const pc = new RTCPeerConnection({iceServers: [{urls:[`turn:${turnAddressV4}`], username, credential}]}); 167 try { 168 const candidates1 = await gatherWithTimeout(pc, 32000, `a turn (udp) server`); 169 ok(candidates1.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 170 ok(candidates1.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 171 await pc.setLocalDescription({type: "rollback"}); 172 173 pc.setConfiguration({}); 174 const candidates2 = await gatherWithTimeout(pc, 32000, `no ICE servers`); 175 ok(!candidates2.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 176 ok(!candidates2.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 177 } finally { 178 pc.close(); 179 } 180 }, 181 182 async function removeTurnTcpServerAfterOffer() { 183 const pc = new RTCPeerConnection({iceServers: [{urls:[`turn:${turnAddressV4}?transport=tcp`], username, credential}]}); 184 try { 185 const candidates1 = await gatherWithTimeout(pc, 32000, `a turn (tcp) server`); 186 ok(!candidates1.some(c => c.candidate.includes("srflx")), "Should get no srflx candidates"); 187 ok(candidates1.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 188 await pc.setLocalDescription({type: "rollback"}); 189 190 pc.setConfiguration({}); 191 const candidates2 = await gatherWithTimeout(pc, 32000, `no ICE servers`); 192 ok(!candidates2.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 193 ok(!candidates2.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 194 } finally { 195 pc.close(); 196 } 197 }, 198 199 async function addStunServerAfterNegotiation() { 200 const offerer = new RTCPeerConnection(); 201 const answerer = new RTCPeerConnection({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 202 try { 203 const candidatePromise = trickleIce(offerer); 204 await connect(offerer, answerer, 32000, `no ICE servers`); 205 const candidates = await candidatePromise; 206 const ufrags = Array.from(new Set(candidates.map(c => c.usernameFragment))); 207 is(ufrags.length, 1, "Should have one ufrag in candidate set"); 208 209 offerer.setConfiguration({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 210 const candidates2 = await gatherWithTimeout(offerer, 32000, `just a stun server`); 211 ok(candidates2.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 212 ok(!candidates2.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 213 const ufrags2 = Array.from(new Set(candidates2.map(c => c.usernameFragment))); 214 is(ufrags2.length, 1, "Should have one ufrag in candidate set"); 215 isnot(ufrags[0], ufrags2[0], "ufrag should change, because setConfiguration should have triggered an ICE restart"); 216 } finally { 217 offerer.close(); 218 answerer.close(); 219 } 220 }, 221 222 async function addTurnServerAfterNegotiation() { 223 const offerer = new RTCPeerConnection(); 224 const answerer = new RTCPeerConnection({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 225 try { 226 const candidatePromise = trickleIce(offerer); 227 await connect(offerer, answerer, 32000, `no ICE servers`); 228 const candidates = await candidatePromise; 229 const ufrags = Array.from(new Set(candidates.map(c => c.usernameFragment))); 230 is(ufrags.length, 1, "Should have one ufrag in candidate set"); 231 232 offerer.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}`], username, credential}]}); 233 const candidates2 = await gatherWithTimeout(offerer, 32000, `a turn (udp) server`); 234 ok(candidates2.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 235 ok(candidates2.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 236 const ufrags2 = Array.from(new Set(candidates2.map(c => c.usernameFragment))); 237 is(ufrags2.length, 1, "Should have one ufrag in candidate set"); 238 isnot(ufrags[0], ufrags2[0], "ufrag should change, because setConfiguration should have triggered an ICE restart"); 239 } finally { 240 offerer.close(); 241 answerer.close(); 242 } 243 }, 244 245 async function addTurnTcpServerAfterNegotiation() { 246 const offerer = new RTCPeerConnection(); 247 const answerer = new RTCPeerConnection({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 248 try { 249 const candidatePromise = trickleIce(offerer); 250 await connect(offerer, answerer, 32000, `no ICE servers`); 251 const candidates = await candidatePromise; 252 const ufrags = Array.from(new Set(candidates.map(c => c.usernameFragment))); 253 is(ufrags.length, 1, "Should have one ufrag in candidate set"); 254 255 offerer.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}?transport=tcp`], username, credential}]}); 256 const candidates2 = await gatherWithTimeout(offerer, 32000, `a turn (tcp) server`); 257 ok(!candidates2.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 258 ok(candidates2.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 259 const ufrags2 = Array.from(new Set(candidates2.map(c => c.usernameFragment))); 260 is(ufrags2.length, 1, "Should have one ufrag in candidate set"); 261 isnot(ufrags[0], ufrags2[0], "ufrag should change, because setConfiguration should have triggered an ICE restart"); 262 } finally { 263 offerer.close(); 264 answerer.close(); 265 } 266 }, 267 268 async function addStunServerBeforeCreateAnswer() { 269 const offerer = new RTCPeerConnection(); 270 const answerer = new RTCPeerConnection(); 271 272 try { 273 await answerer.setRemoteDescription(await offerer.createOffer({offerToReceiveAudio: true})); 274 275 answerer.setConfiguration({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 276 const candidates = await gatherWithTimeout(answerer, 32000, `just a stun server`); 277 ok(candidates.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 278 ok(!candidates.some(c => c.candidate.includes("relay")), "Should not get any relay candidates"); 279 } finally { 280 offerer.close(); 281 answerer.close(); 282 } 283 }, 284 285 async function addTurnServerBeforeCreateAnswer() { 286 const offerer = new RTCPeerConnection(); 287 const answerer = new RTCPeerConnection(); 288 289 try { 290 await answerer.setRemoteDescription(await offerer.createOffer({offerToReceiveAudio: true})); 291 292 answerer.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}`], username, credential}]}); 293 const candidates = await gatherWithTimeout(answerer, 32000, `a turn (udp) server`); 294 ok(candidates.some(c => c.candidate.includes("srflx")), "Should get at least one srflx candidate"); 295 ok(candidates.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 296 } finally { 297 offerer.close(); 298 answerer.close(); 299 } 300 }, 301 302 async function addTurnTcpServerBeforeCreateAnswer() { 303 const offerer = new RTCPeerConnection(); 304 const answerer = new RTCPeerConnection(); 305 306 try { 307 await answerer.setRemoteDescription(await offerer.createOffer({offerToReceiveAudio: true})); 308 309 answerer.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}?transport=tcp`], username, credential}]}); 310 const candidates = await gatherWithTimeout(answerer, 32000, `a turn (tcp) server`); 311 ok(!candidates.some(c => c.candidate.includes("srflx")), "Should not get any srflx candidates"); 312 ok(candidates.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 313 } finally { 314 offerer.close(); 315 answerer.close(); 316 } 317 }, 318 319 async function relayPolicyPreventsSrflx() { 320 const pc = new RTCPeerConnection(); 321 try { 322 pc.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}`], username, credential}], iceTransportPolicy: "relay"}); 323 const candidates = await gatherWithTimeout(pc, 32000, `a turn (udp) server`); 324 ok(!candidates.some(c => c.candidate.includes("srflx")), "Should not get a srflx candidate"); 325 ok(candidates.some(c => c.candidate.includes("relay")), "Should get at least one relay candidate"); 326 } finally { 327 pc.close(); 328 } 329 }, 330 331 async function addOffererStunServerAllowsIceToConnect() { 332 const offerer = new RTCPeerConnection(); 333 const answerer = new RTCPeerConnection(); 334 335 try { 336 try { 337 // Both ends are behind a simulated endpoint-independent NAT, which 338 // requires at least one side to have a srflx candidate to work. 339 await connect(offerer, answerer, 2000, `no ICE servers`); 340 ok(false, "ICE should either have failed, or timed out!"); 341 } catch (e) { 342 if (!(e instanceof Error)) throw e; 343 ok(true, "ICE should either have failed, or timed out!"); 344 } 345 346 offerer.setConfiguration({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 347 await connect(offerer, answerer, 32000, `just a STUN server`); 348 } finally { 349 offerer.close(); 350 answerer.close(); 351 } 352 }, 353 354 async function addAnswererStunServerDoesNotAllowIceToConnect() { 355 const offerer = new RTCPeerConnection(); 356 const answerer = new RTCPeerConnection(); 357 358 try { 359 try { 360 // Both ends are behind a simulated endpoint-independent NAT, which 361 // requires at least one side to have a srflx candidate to work. 362 await connect(offerer, answerer, 2000, `no ICE servers`); 363 ok(false, "ICE should either have failed, or timed out!"); 364 } catch (e) { 365 if (!(e instanceof Error)) throw e; 366 ok(true, "ICE should either have failed, or timed out!"); 367 } 368 369 // This _won't_ help, because the answerer does not get to decide to 370 // trigger an ICE restart. 371 answerer.setConfiguration({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 372 try { 373 await connectNoTrickleWait(offerer, answerer, 2000, `no ICE servers`); 374 ok(false, "ICE should either have failed, or timed out!"); 375 } catch (e) { 376 if (!(e instanceof Error)) throw e; 377 ok(true, "ICE should either have failed, or timed out!"); 378 } 379 } finally { 380 offerer.close(); 381 answerer.close(); 382 } 383 }, 384 385 async function addOffererTurnServerAllowsIceToConnect() { 386 await pushPrefs( 387 ['media.peerconnection.nat_simulator.filtering_type', 'PORT_DEPENDENT'], 388 ['media.peerconnection.nat_simulator.mapping_type', 'PORT_DEPENDENT']); 389 390 const offerer = new RTCPeerConnection({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 391 const answerer = new RTCPeerConnection({iceServers: [{urls:[`stun:${turnAddressV4}`]}]}); 392 393 try { 394 try { 395 // Both ends are behind a simulated port-dependent NAT, which 396 // requires at least one side to have a relay candidate to work. 397 await connect(offerer, answerer, 2000, `just a STUN server`); 398 ok(false, "ICE should either have failed, or timed out!"); 399 } catch (e) { 400 if (!(e instanceof Error)) throw e; 401 ok(true, "ICE should either have failed, or timed out!"); 402 } 403 404 offerer.setConfiguration({iceServers: [{urls:[`turn:${turnAddressV4}`], username, credential}]}); 405 await connect(offerer, answerer, 32000, `a TURN (udp) server`); 406 } finally { 407 offerer.close(); 408 answerer.close(); 409 await SpecialPowers.popPrefEnv(); 410 } 411 }, 412 413 ]; 414 415 runNetworkTest(async () => { 416 const turnServer = iceServersArray.find(server => "username" in server); 417 username = turnServer.username; 418 credential = turnServer.credential; 419 // Just use the first url. It might make sense to look for TURNS first, 420 // since that will always use a hostname, but on CI we don't have TURNS 421 // support anyway (see bug 1323439). 422 const turnHostname = getTurnHostname(turnServer.urls[0]); 423 turnAddressV4 = await dnsLookupV4(turnHostname); 424 425 await pushPrefs( 426 ['media.peerconnection.ice.obfuscate_host_addresses', false], 427 ['media.peerconnection.nat_simulator.filtering_type', 'ENDPOINT_INDEPENDENT'], 428 ['media.peerconnection.nat_simulator.mapping_type', 'ENDPOINT_INDEPENDENT'], 429 ['media.peerconnection.ice.loopback', true], 430 ['media.getusermedia.insecure.enabled', true]); 431 432 for (const test of tests) { 433 info(`Running test: ${test.name}`); 434 try { 435 await test(); 436 } catch (e) { 437 ok(false, `Caught ${e.name}: ${e.message} ${e.stack}`); 438 } 439 info(`Done running test: ${test.name}`); 440 // Make sure we don't build up a pile of GC work, and also get PCImpl to 441 // print their timecards. 442 await new Promise(r => SpecialPowers.exactGC(r)); 443 } 444 445 await SpecialPowers.popPrefEnv(); 446 }, { useIceServer: true }); 447 </script> 448 </pre> 449 </body> 450 </html>