tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ice-state.https.html (4703B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <meta name="timeout" content="long">
      4 <title>RTCPeerConnection Failed State</title>
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="../RTCPeerConnection-helper.js"></script>
      8 <script>
      9 'use strict';
     10 
     11 // Tests for correct behavior of ICE state.
     12 
     13 // SDP copied from JSEP Example 7.1
     14 // It contains two media streams with different ufrags, and bundle
     15 // turned on.
     16 const kSdp = `v=0
     17 o=- 4962303333179871722 1 IN IP4 0.0.0.0
     18 s=-
     19 t=0 0
     20 a=ice-options:trickle
     21 a=group:BUNDLE a1 v1
     22 a=group:LS a1 v1
     23 m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98
     24 c=IN IP4 203.0.113.100
     25 a=mid:a1
     26 a=sendrecv
     27 a=rtpmap:96 opus/48000/2
     28 a=rtpmap:0 PCMU/8000
     29 a=rtpmap:8 PCMA/8000
     30 a=rtpmap:97 telephone-event/8000
     31 a=rtpmap:98 telephone-event/48000
     32 a=maxptime:120
     33 a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
     34 a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level
     35 a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9
     36 a=ice-ufrag:ETEn
     37 a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl
     38 a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
     39 a=setup:actpass
     40 a=dtls-id:1
     41 a=rtcp:10101 IN IP4 203.0.113.100
     42 a=rtcp-mux
     43 a=rtcp-rsize
     44 m=video 10102 UDP/TLS/RTP/SAVPF 100 101
     45 c=IN IP4 203.0.113.100
     46 a=mid:v1
     47 a=sendrecv
     48 a=rtpmap:100 VP8/90000
     49 a=rtpmap:101 rtx/90000
     50 a=fmtp:101 apt=100
     51 a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
     52 a=rtcp-fb:100 ccm fir
     53 a=rtcp-fb:100 nack
     54 a=rtcp-fb:100 nack pli
     55 a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0
     56 a=ice-ufrag:BGKk
     57 a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf
     58 a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
     59 a=setup:actpass
     60 a=dtls-id:1
     61 a=rtcp:10103 IN IP4 203.0.113.100
     62 a=rtcp-mux
     63 a=rtcp-rsize
     64 `;
     65 
     66 // Returns a promise that resolves when |pc.iceConnectionState| is in one of the
     67 // wanted states, and rejects if it is in one of the unwanted states.
     68 // This is a variant of the function in RTCPeerConnection-helper.js.
     69 function waitForIceStateChange(pc, wantedStates, unwantedStates=[]) {
     70  return new Promise((resolve, reject) => {
     71    if (wantedStates.includes(pc.iceConnectionState)) {
     72      resolve();
     73      return;
     74    } else if (unwantedStates.includes(pc.iceConnectionState)) {
     75      reject('Unexpected state encountered: ' + pc.iceConnectionState);
     76      return;
     77    }
     78    pc.addEventListener('iceconnectionstatechange', () => {
     79      if (wantedStates.includes(pc.iceConnectionState)) {
     80        resolve();
     81      } else if (unwantedStates.includes(pc.iceConnectionState)) {
     82        reject('Unexpected state encountered: ' + pc.iceConnectionState);
     83      }
     84    });
     85  });
     86 }
     87 
     88 promise_test(async t => {
     89  const pc1 = new RTCPeerConnection();
     90  const pc2 = new RTCPeerConnection();
     91  t.add_cleanup(() => pc1.close());
     92  t.add_cleanup(() => pc2.close());
     93  let [track, streams] = await getTrackFromUserMedia('video');
     94  const sender = pc1.addTrack(track);
     95  exchangeIceCandidates(pc1, pc2);
     96  await exchangeOfferAnswer(pc1, pc2);
     97  await waitForIceStateChange(pc1, ['connected', 'completed']);
     98 }, 'PC should enter connected (or completed) state when candidates are sent');
     99 
    100 promise_test(async t => {
    101  const pc1 = new RTCPeerConnection();
    102  t.add_cleanup(() => pc1.close());
    103  let [track, streams] = await getTrackFromUserMedia('video');
    104  const sender = pc1.addTrack(track);
    105  const offer = await pc1.createOffer();
    106  assert_greater_than_equal(offer.sdp.search('a=ice-options:trickle'), 0);
    107 }, 'PC should generate offer with a=ice-options:trickle');
    108 
    109 promise_test(async t => {
    110  const pc1 = new RTCPeerConnection();
    111  t.add_cleanup(() => pc1.close());
    112  await pc1.setRemoteDescription({type: 'offer', sdp: kSdp});
    113  const answer = await pc1.createAnswer();
    114  await pc1.setLocalDescription(answer);
    115  assert_greater_than_equal(answer.sdp.search('a=ice-options:trickle'), 0);
    116  // When we use trickle ICE, and don't signal end-of-caniddates, we
    117  // expect failure to result in 'disconnected' state rather than 'failed'.
    118  const stateWaiter = waitForIceStateChange(pc1, ['disconnected'],
    119                                            ['failed']);
    120  // Add a bogus candidate. The candidate is drawn from the
    121  // IANA "test-net-3" pool (RFC5737), so is guaranteed not to respond.
    122  const candidateStr1 =
    123      'candidate:1 1 udp 2113929471 203.0.113.100 10100 typ host';
    124  await pc1.addIceCandidate({candidate: candidateStr1,
    125                             sdpMid: 'a1',
    126                             usernameFragment: 'ETEn'});
    127  await stateWaiter;
    128 }, 'PC should enter disconnected state when a failing candidate is sent');
    129 
    130 </script>