New WebRTC transport?

Let’s consider two js-libp2p nodes running on the browser, Bob and Alice.

There are currently 2 WebRTC transports for libp2p:

  • /p2p-webrtc-star/ which allows direct connection between 2 browsers, but that requires a rendez-vous server that nodes connect to using WebSocket and that is run by one of the peers or someone else. Another disadvantage is that both Bob and Alice must connect to the signaling server before the connection. What it means is that if only Bob wants to connect to Alice, it doesn’t work, because Alice is never aware of that.
  • /p2p-webrtc-direct/ that doesn’t need any rendez-vous server or any other entity than the 2 nodes we want to connect. But because it exchanges the WebRTC handshake data (SDP and ICE candidates) in a HTTP request, it only works for browser=>server or server=>server connections.

As we see, as of right now there is no transport for directly connecting two browsers without them relying on a signaling server that adds centralization. Then there is the much hyped circuit relay (URL: docs.libp2p. io/concepts/circuit-relay, new users can only put 2 links) that will hopefully be implemented sometime soon in libp2p. Here is an example of multiaddress using circuit relay:

In a nutshell, circuit relay routes all the communication between the 2 peers in a circuit of nodes of the network. But doing this is a bit overkill, we don’t need the relay all the time with WebRTC, we only need it for the signaling, then we can establish a direct connection between the 2 peers.

So I think we need a third WebRTC transport (let’s name it /p2p-webrtc-relay/ for the sake of the explanation). It would operate like this for example:

  • Bob adds the /ip4/RelayIP/tcp/RelayPort/wss/p2p/RelayPeerId/p2p-webrtc-relay/p2p/AlicePeerId multiaddress,
  • Bob connects to the relay node (Go or Node.js) using WebSocket,
  • The relay tries to establish a circuit between Bob and Alice,
  • Once a circuit is found, the handshake data is exchanged between the 2 peers (i.e. the SDP and the ICE candidates),
  • The direct WebRTC connection between Alice and Bob is finally established and the circuit relay can be dropped.

Of course, this would require first to have a stable implementation of circuit relay, which is not the case right now, but once it is done this would be (I think) the first time a practical way has been found to establish a WebRTC connection between 2 browsers in a truly peer-to-peer manner.

What do you think?

1 Like

Lemme preface by saying that I don’t know much about WebRTC, but lemme make a few following points:

  1. In my recollection, p2p-circuit is implemented correctly in go-ipfs, which (afaik) makes up the majority of the network as of this moment, so using this relay technique would actually work nicely as long as both browsers are connected to the same nodes, yes.
  2. Is there an explicit need for browser-browser? Browser nodes are often extremely short-lived on the network, as their lifetime is often bound to the lifetime of the webpage session they exist on. When using window.ipfs, the client essentially becomes a locally-wound-up js-ipfs client, or the machine’s host client, making use of the facilities and transport options of that machine.

Oh ok, it explains how PubSub can work between browsers then.

Well yes, otherwise there would be no point in implementing WebRTC transport in libp2p, we could do everything with WebSocket and connect all browser nodes with Go or Nodes.js nodes.

I can take me as an example, what I want to do is a completely peer-to-peer web game, so I have to use WebRTC. But I don’t even want STUN, TURN or signaling servers, so I dismissed the PeerJS library because it uses a connection broker server.

But I don’t want to reinvent the wheel either. The idea I gave here only applies if there is a large enough network that can do relaying to replace STUN and TURN serverlessly, so libp2p is perfect for that.

When I can leverage the speed of direct browser-to-browser WebRTC connections, I don’t see why I would still use relay for the communication in my game. I don’t know if PubSub (that uses relay if I’m not mistaken) would be able to handle all the traffic of a web game, and I don’t know if there is someone in the libp2p network who would be willing to sacrifice their bandwidth so that every communication of the game would be relayed through their go-libp2p node.

I don’t think that’s true, it would be like saying that Go nodes cease to exist when the computer shuts down. It doesn’t happen because the public/private key pair persists on your computer’s hard disk (in the local storage of the browser in the case of js-libp2p).

But I would agree that connections (and not nodes) are extremely short-lived on the browser, because as soon as you close your browser, your NAT could close the port it has opened for you. But when you reopen your browser and relaunch your libp2p node using the same key, you can connect to the swarm and your friends can contact you again because you will have the same /p2p/ key, although your multiaddr might have changed (especially the /tcp/ part). You just have to do NAT hole-punching and peer discovery again.

But even if nodes were extremely short-lived on the browser, I would say it’s not really a problem 90% of the time because the need is not the same between the browser version of libp2p and the Go version. In Go, you want to have a full-fledged client that is stable, can do automatic port forwarding etc. while in the browser most of the time you want to use libp2p as an abstraction of the WebRTC API to directly connect browsers between them and do clever apps like a peer-to-peer chat or a collaborative editing application. Often, you don’t care if your libp2p instance is not the same when you restart your browser.

Ok I now have the answer, decentralizing WebRTC signaling is already a WIP for js-libp2p:

The only question remaining is, when will we have a stable implementation of it?