wngr / libp2p-webrtc

WebRTC transport for libp2p (native and wasm)
Apache License 2.0
29 stars 4 forks source link

Host discovery #1

Open sireliah opened 2 years ago

sireliah commented 2 years ago

Hi, firstly, congratulations for making working implementation of the webrtc for libp2p!

I was interested in your implementation of the signalling server and I noticed that it doesn't cover exchanging the candidates for the connection. In other words, peer can connect to another peer if their addresses has been exchanged through some different channel.

What I was planning to do was to send ice candidate message to some subset of connected peers just after the websocket connection has been established with the new peer.

On the higher level, the swarm of a connected peer would produce an event, something like NewCandidate with address of the newly connected peer. That would work similarly to how snapdrop is dealing with peer discovery.

From implementation point of view it would be most reasonable to build new network behaviour (like mdns) and send candidates not even touching libp2p-webrtc transport. The problem is that the network behaviour doesn't have access to the websocket connections with peers (AFAIK).

Did you have thoughts about this problem? What are possibilities of solving it through this library?

Please let me know if my explanation was not clear or I confused any webrtc concepts.

wngr commented 2 years ago

Hey! Thanks for your feedback.

First of all, the state and workings of this crate is subject to change. I was thinking about a) making it compatible with libp2p-webrtc-star signaling from js-libp2p, and/or b) looking into other means of exchanging sdp data (maybe through https://github.com/libp2p/rust-libp2p/pull/2076), and/or c) relying on webrtc specifics, such as ice candidates and re-using the actual encryption (not adding an additional noise layer).

I was interested in your implementation of the signalling server and I noticed that it doesn't cover exchanging the candidates for the connection. In other words, peer can connect to another peer if their addresses has been exchanged through some different channel.

That's right, my idea so far was to use other discovery mechanisms, such as rendez-vous or gossipsub, for exchanging addresses. The signaling server should eventually go away, and be replaced with something within the libp2p ecosystem (see above).

What I was planning to do was to send ice candidate message to some subset of connected peers just after the websocket connection has been established with the new peer.

On the higher level, the swarm of a connected peer would produce an event, something like NewCandidate with address of the newly connected peer. That would work similarly to how snapdrop is dealing with peer discovery.

Okay, so your idea is to just broadcast new peers to any connected peers via the signaling server, out of band of lipbp2? Not sure I understand your intention with the ice candidate messages. Right now, you tell libp2p to connect to /dns4/my-signaling-server/tcp/4242/ws/p2p-webrtc-star/<target_peer_id>, and this is the multiaddr to exchange via some external discovery mechanism. After that, all WebRTC related data, such as ice candidates, is exchanged through the signaling server at /dns4/my-signaling-server/tcp/4242 with <target_peer_id>. So far, I hid all the WebRTC specifics; maybe that's where some potential confusion stems from.

From implementation point of view it would be most reasonable to build new network behaviour (like mdns) and send candidates not even touching libp2p-webrtc transport. The problem is that the network behaviour doesn't have access to the websocket connections with peers (AFAIK).

You mean the connection to the other peer via the signaling server? Right, that's not possible at the moment.

Did you have thoughts about this problem? What are possibilities of solving it through this library?

So I think there are two conflating points here:

  1. Discovery mechanism: This is to be solved through other means, not this library. We could expose the WS connection though, but I think this is a bad idea (see next point).
  2. Improvements of this transports by relying on WebRTC specifics, such as ICE candidates, to eventually get rid of the WS signalling server.

By the way, @mxinden told me that WebRTC will be a bigger focus next year for Protocol Labs.

sireliah commented 2 years ago

Thanks for the answer!

Okay, so your idea is to just broadcast new peers to any connected peers via the signaling server, out of band of lipbp2?

Yeah, pretty much. I wanted to implement local network host discovery with the help of signalling server. I have desktop app that uses libp2p with mdns to discover peers in the local network and I was willing do achieve similar result in the browser by grouping peers by public IP address.

And yeah, I confused what ICE candidates mean in WebRTC, sorry. What I really was interested in was host discovery.

We could expose the WS connection though, but I think this is a bad idea (see next point).

I agree with that, because applications using the library shouldn't rely on internals of the lib.

Improvements of this transports by relying on WebRTC specifics, such as ICE candidates, to eventually get rid of the WS signalling server.

Thanks again for the clarification. I think I can proceed without browser-to-browser discovery for now.

wngr commented 2 years ago

Maybe a viable solution for you would be to amend the signaling server with a libp2p node offering a rendezvous point for host discovery. I did exactly that for another project.

sireliah commented 2 years ago

Do you mean to run libp2p rendezvous on signalling server? Would you mind linking your project?

sireliah commented 2 years ago

By the way, I've read that there is ongoing work in making some browsers work natively with mdns (which can be used to discover services). This sounded promising, but reading through the ietf draft suggests that the intention was to actually prevent the browser from accessing any IP addresses of peers. That solution might not help.

wngr commented 2 years ago

It's not public (yet). But the gist of the discovery mechanism would be to follow the example of the rendezvous protocol from https://github.com/libp2p/rust-libp2p/blob/303490103b8c1641b9182b622810639a1c86b739/protocols/rendezvous/examples/rendezvous_point.rs#L33-L40

And in your client code you'd connect to the rendezvous server, and handle the Discovered event:

            SwarmEvent::Behaviour(Event::Rendezvous(rendezvous::client::Event::Discovered {
                registrations,
                cookie,
                ..
            })) => {
                self.discovery_token.replace(cookie);
                for r in registrations {
                    let peer = r.record.peer_id();
                    info!("Discovered new peer {} ({:?})", peer, r.record.addresses());
                    for a in r.record.addresses() {
                        let p2p_suffix = Protocol::P2p(*peer.as_ref());
                        let a_with_p2p =
                            if !a.ends_with(&Multiaddr::empty().with(p2p_suffix.clone())) {
                                a.clone().with(p2p_suffix)
                            } else {
                                a.clone()
                            };
                        let _ = self.swarm.dial(a_with_p2p);
                    }
                }
            }
sireliah commented 2 years ago

I implemented the server without trouble, but I've found out that the client is a bit more tricky, because rendezvous requires tcp transport.

error[E0432]: unresolved import `libp2p::tcp`
  --> src/lib.rs:10:5
   |
10 |     tcp::TcpConfig, Multiaddr, NetworkBehaviour, PeerId, Swarm, Transport,
   |     ^^^ could not find `tcp` in `libp2p`

My best guess is that tcp is not exported for wasm32, because browsers do not have access to OS TCP stack.

Briefly checking the rendezvous code I saw that it is using protobuf as the format, so maybe a websocket transport would be a good alternative to tcp (since browsers natively support websockets in Javascript). I'll try to figure out if this could be implemented in rendezvous.

It's a problem that is no longer related to WebRTC, so please feel free to close this issue. Thanks for the ideas for the discovery!

wngr commented 2 years ago

Not sure I understand your problem. The rendezvous behaviour protocol (both server and client) is transport agnostic.

Anyway, happy to help out further, but maybe not in this issue.

[..], so please feel free to close this issue.

I'll leave the ticket open. I feel there are some points in this that need to be addressed in the future.