pion / webrtc

Pure Go implementation of the WebRTC API
https://pion.ly
MIT License
13.79k stars 1.66k forks source link

Data-channels not working in Docker #353

Closed Parth closed 5 years ago

Parth commented 5 years ago

Data-channels not working in Docker

Hi! I'm using WebRTC for a game, the back-end is written in go, and the frontend is a browser client. Thanks to this library I was able to drop in WebRTC in place of websockets. The network performance is significantly better, this is an awesome project!

I do however have an issue running this within docker locally. So my gameserver can run within docker, or directly as a binary (just like the data-channels example), and it can run locally, or in the cloud. The following depicts what works and what doesn't.

Locally Cloud
Execute Binary Directly Works Works
Execute Within Docker Error Works

Reproducing

This can be easily replicated using the data-channels example:

  1. First open the fiddle frontend.
  2. In a local directory copy the Browser SDP to a file named sdp.
  3. Place the Dockerfile provided below into this directory.
  4. Execute: docker build -t data-channels . && docker run data-channels

This is likely a docker issue, and perhaps I should create a ticket there. But I get the sense that many people who use WebRTC will be interested in using it with Docker, however not everyone who uses Docker will be using WebRTC.

Thank you!

Dockerfile

FROM golang:1.10

WORKDIR /files
COPY sdp .
RUN cat /files/sdp

RUN go get github.com/pions/webrtc/examples/data-channels

CMD ["/bin/sh", "-c", "cat sdp | data-channels"]

Some other logs, that google didn't really offer much help with:

could not allocate udp6 stun:stun.l.google.com:19302: Failed to create STUN client: dial udp6 [2607:f8b0:400d:c0d::7f]:19302: connect: cannot assign requested address
could not allocate udp6 stun:stun.l.google.com:19302: Failed to create STUN client: dial udp6 [2607:f8b0:400d:c0d::7f]:19302: connect: cannot assign requested address

I attempted to change these sysctl settings on the host computer, but this issue has been replicated in macOS & Windows as well, my host environment is Ubuntu 18.04.

net.ipv6.conf.all.forwarding=1
Sean-Der commented 5 years ago

Hey @Parth Thanks for using pion-WebRTC, I am really excited to see the game you are working on when it is complete :)

So my assumption is that Chromium is creating ICE candidates using interfaces that don't route to your Docker container (so it is unable to communicate) a good way to see how this all works is using the ICE debugging stuff. Sorry it isn't documented but here is the commit that added it! I would enable it to compare.

This issue with networking also only exists on OSX/Windows unfortunately, because it puts all containers behind a NAT. I am not positive this will work, but can you calling this and then mapping these ports?

You could also try running your browser inside your containers.

My last idea would be to play with PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS it is a feature of Chromium, I have never actually used it before (sorry!)

Happy to debug/throw ideas around in Slack also. We will find a way to figure it out though :)

backkem commented 5 years ago

I did some quick testing on my end. I'm running on Windows where docker has its own network adapter that places all containers behind a NAT, as Sean mentioned. If I run data-channels from a container I can connect using Chrome but not using Firefox. Firefox doesn't include an IP address of the Docker NAT in it's offer. I'm not sure if Firefox has a setting for this.

Parth commented 5 years ago

Hey guys, thanks for all the resources!

Few questions:

I'd love to continue the conversation on Slack, slack says.

Contact the workspace administrator for an invitation

my email is parth.mehrotra.cs@gmail.com

After we get this resolved I can leave a summary of what worked and close this issue (for future people who have similar problems with WebRTC/docker).

backkem commented 5 years ago

Hey, Some notes:

I'll try to brainstorm a workaround for this problem.

backkem commented 5 years ago

After some digging I found this issue. Firefox apparently implements these guidelines. They restrict the IP information that is allowed to be used without explicit user consent. To test this theory I checked the SDP for the gstreamer-receive example. This example indeed has the Docker NAT candidates in the SDP because of the consent provided when calling getUserMedia. I'll try to investigate if we can manually ask for permissions somehow.

backkem commented 5 years ago

Sadly I think the only workaround available in Firefox at the moment is to also request user media. More related issues:

Alternatively, I would suggest using Chrome for testing when using Docker.

Parth commented 5 years ago

Hey, Caught up with some other work at the moment, will report back soon!

Parth commented 5 years ago

Okay you gave me a bunch of good resources to go through, and this is my current understanding:

In certain conditions ICE has the potential to expose information about the client's network stack. This can be particularly bad if the client is behind a VPN. But if they're behind a VPN for reasons other than privacy (corporate network) they still may prefer to connect to their peer directly and may not care.

Because of this interesting tradeoff between privacy & media performance the draft suggests 4 modes that browsers can operate in.

By default the data-channels operate in a mode where they can't communicate with devices on a different interface, as chrome prevents some of those addresses from being known (still a bit unclear here, but I understand what's happening at a high level. I think I need to read a bit more about how network interfaces work & docker networking interfaces).

So what I can do is (when testing locally) call getUserMedia() during/before handshake and that will allow chrome to speak to a broader range of network devices.

Is this the correct workaround? Again it doesn't matter all that much what the form of the workaround is because this only affects engineers who are developing locally. So if we need to do something like "change setting X in browser Y" that's totally fine with us. In fact, something like that is preferred to adding getUserMedia() for local development. But you mentioned:

Alternatively, I would suggest using Chrome for testing when using Docker.

and I'm just not sure what I should do to get it to work, I've only used chrome so far.

Thanks again for your time and energy!

backkem commented 5 years ago

Using Chrome did work on my machine. I was only able to reproduce using FF. I'm not sure what we're doing differently. For me:

Parth commented 5 years ago

Let me give this a shot with:

Will report back