Simple-peer: Chrome mDNS breaks connections to Safari and Firefox

Created on 13 Jul 2019  路  22Comments  路  Source: feross/simple-peer

The simple example in the README works great in Chrome and Firefox.

In Safari, I get the dreaded "ice connection failed". This comment: https://github.com/feross/simple-peer/issues/202#issuecomment-435717976 suggests that Safari disables ICE unless you open an audio/video stream. However, WebTorrent seems to be getting ICE candidates just fine with underlying simple-peer. Is there a workaround?

bug dependencbrowser

Most helpful comment

Safari will generate a local host candidate if you call getusermedia() before constructing the peer connection.

All 22 comments

You should still be getting srflx candidates. Can you log your signalling data and post it in a gist?

Yes. There are srflx candidates. The absence of a host candidate seems to be critical somehow.
I am running Safari 12.1.1 (14607.2.6.1.1) on macOS 10.14.5.

I am attaching logs with and without trickle, because I noticed that sometimes I can get Safari to connect to a Chrome peer with trickle: false. But it is not consistent (which alone is pretty weird, I have even set up a local signalhubws).

with trickle=true: https://gist.github.com/corwin-of-amber/7bc454e406af1823f703c18ffb02e3ce
with trickle=false: https://gist.github.com/corwin-of-amber/40bd58860eb2271d8af8bf3e45244e2e

To be clear, this is the code I was running (taken from the main page, with extra prints added):


var Peer = require('simple-peer')

var peer1 = new Peer({initiator: true})
var peer2 = new Peer({})

peer1.on('signal', data => {
  // when peer1 has signaling data, give it to peer2 somehow
  console.log(`peer1->peer2 signal ${JSON.stringify(data)}`);
  peer2.signal(data)
})

peer2.on('signal', data => {
  // when peer2 has signaling data, give it to peer1 somehow
  console.log(`peer2->peer1 signal ${JSON.stringify(data)}`);
  peer1.signal(data)
})

peer1.on('connect', () => {
  // wait for 'connect' event before using the data channel
  peer1.send('hey peer2, how is it going?')
})

peer2.on('data', data => {
  // got a data channel message
  console.log('got a message from peer1: ' + data)
})

What candidates do you get on Safari from this:
https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/

Same, only srflx.
Screen Shot 2019-07-14 at 20 38 27

and, as expected, I get host as well if I run getUserMedia first.
Screen Shot 2019-07-14 at 20 41 07

I may be mistaken. Looking at the specification, it seems srflx candidates are only used with respect to a host candidate and aren't sufficient on their own.

I'm not sure how WebTorrent works around this issue, there's nothing obvious I could find.

It is possible that a host candidate from one side is sufficient, as in the case of Safari<->Chrome, but I haven't been able to figure out when it works and when it doesn't.

BTW Chrome gives a very weird host address.
Screen Shot 2019-07-14 at 20 50 40

I think you'll need to use getusermedia in Safari<->Safari, but we can investigate why Chrome<->Safari isn't working sometimes even when Chrome gets a host candidate.

The weird host candidate from Chrome is in fact the culprit in Chrome<->Safari connection issues.
When I intrusively inserted the following line before calling signal:

data.signal.candidate.candidate = data.signal.candidate.candidate.replace(/[a-z0-9\-]+\.local/, '192.168.1.2');

With my hard-coded LAN IP, Chrome and Safari connect successfully.
I guess there is not much that can be done, unless there is some hidden setting for address format.

The weird host candidate is an mDNS domain name, not an IP address. It's a Chrome experiment that is running on random browsers (which explains why this issue can't be reproduced).

https://tools.ietf.org/html/draft-ietf-rtcweb-mdns-ice-candidates-03
https://bloggeek.me/psa-mdns-and-local-ice-candidates-are-coming/

I think we should just filter out these candidates in browsers that don't support them (which I think is everything but Chrome, but I need to check).

Huh. The world is a complicated place.

But then we are left again without a host candidate in the Chrome<->Safari connection, since Safari does not generate one and Chrome's will be filtered out.

Safari will generate a local host candidate if you call getusermedia() before constructing the peer connection.

Yes, that one is known to me. I find this to be a non-solution as it requires the user to authorize the web app to access the camera or microphone. Which is why the original title for this issue was "Data only connection" etc.

That was really interesting reading material, thanks @t-mullen. Connection sort-of works between Safari and Chrome now that I have disabled chrome://flags/#enable-webrtc-hide-local-ips-with-mdns. I guess this is not a long-term solution but it least now I know what the problem is.

How about having simple-peer issue a console.warn when trying to connect with no host candidates?

simple-peer should probably throw an error if no host candidates are detected and trickle is disabled (or after the trickle timeout) - before ice connection fails.

There's really no other way to make a local connection with two Safari peers (or with a "broken" Chrome peer and a Safari peer) unless you call getusermedia. Keep in mind you don't have to do this if the peers are on different networks - the remote host candidates from your STUN server will work fine.

if no ice candidates are detected

or if only srflx candidates have been detected (from both sides).

You have been most helpful. I can almost write the code that checks for the absence of candidates, except that for trickle: false, the candidates are tucked inside the offer/answer, so it would be a bit tricky to detect (and perhaps it would be better for simple-peer to remain agnostic to the format of signals).

Anyway IMHO it should be a warning, connection can still be made without candidates if someone wants to use a TURN server.

Yes, I should have said no host or relay candidates. (Which accounts for TURN).

We already throw a Ice connection failed error in this case, but we should be more descriptive about WHY ice failed.

Chrome's use of mDNS also breaks connections to Firefox when peers are on the same network.

Firefox supports the mDNS ICE candidates, but the mDNS address in the c= line of the SDP can't be parsed. https://bugzilla.mozilla.org/show_bug.cgi?id=1562967

Error: OperationError: Failed to parse SDP: SDP Parse Error on line 8:  Error parsing address de8 for mcast.

Nothing can be done here but disable mDNS in Chrome. It's impossible to make a connection without the c= line.

Cool - thanks for the update!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mmorainville picture mmorainville  路  4Comments

Applicafroguy picture Applicafroguy  路  3Comments

measwel picture measwel  路  4Comments

mullerivan picture mullerivan  路  4Comments

sahil-devzila picture sahil-devzila  路  3Comments