Sequence of offer/answer in WebRTC P2P mesh topology - javascript

I am using a web socket server (node JS) to act as a signaling server. I want to create a P2P mesh network - everyone is connected to each other.
What would be the order of operations/events when:
The 1st peer joins
The subsequent peers join
Do every connecting peer send an offer to the signaling server that is then sent to all other connected peers? I am unsure whether this is the right approach.

If what you are trying to do is create a mesh network with audio and video flowing at all times to everyone via a mesh network then I'd suggest reconsidering. Getting this to more than 3 or 4 users to work well is hard to impossible to achieve. See here for an explanation of what goes on the network for different network topologies: http://testrtc.com/different-multiparty-video-conferencing/
If you are trying to do this to get data connected (non voice or video), then you can do that, but again, the number of peer connections you can place in a single browser is limited and each one you add puts some overhead. Today, I wouldn't try to get this over 40 or 50 at most.
By your question, I am assuming all clients will be connected to your server via a WebSocket. You will probably end up routing messages through the server and creating peer connections judiciously when you want to connect a specific user to another one - or a small group of users together.
For the group scenario, I'd use an SFU model - look at Jitsi (https://jitsi.org/Projects/JitsiVideobridge) and Kurento (http://www.kurento.org/) for possible alternatives.

WebRTC connects client to client. If your client connects to at least one other - the other can have a list of others, as the others also has a list of as many others they possible can know. Then it propagates fast. The topology in the list is up to you. Signaling is not needed, because the information to connect with others is in the list.

Related

Is it possible and plausible to implement a WebService over a WebRTC Data Channel?

Is it possible to implement a WebService over a WebRTC Data Channel ?
The idea is:
The client makes one https request to the server for signaling and session establishment
The client and the server start to communicate via a WebRTC DataChannel bidirectionally
Benefits?:
Performance ?
Requests goes over one connection and the standard allows for multiple datachannels over the same connection ( ports )
Flexible networking topologies
UDP
End to end encryption
The server can send events over the same connection
Load balancing could be implemented from a pool of servers client side without a load balancer , or all kinds of different solutions
Currently being debated the addition of DataChannels to Workers/Service Workers/ etc https://github.com/w3c/webrtc-extensions/issues/64
Drawbacks:
Application specific code for implementing request fragmentation and control over buffer limits
[EDIT 3] I don't know how much of a difference in terms of performance and cpu/memory usage will it be against HTTP/2 Stream
Ideas:
Clients could be read replicas of the data for sync, or any other applications that are suitable for orbit-db https://github.com/orbitdb/orbit-db in the public IPFS network, the benefit of using orbit-db is that only allows to the owner to make writes, then the server could additionally sign with his key all the data so that the clients could verify and trust it's from the server, that could offload the main server for reads, just an idea.
[EDIT]
I've found this repo: https://github.com/jsmouret/grpc-over-webrtc
amazing!
[EDIT2]
Changed Orbit-db idea and removed cluster IPFS after investigating a bit
[EDIT3]
After searching Fetch PROS for HTTP/2 i've found Fetch upload streaming with ReadableStreams, i don't know how much of a difference will it be to run GRPC (bidi) over a WebRTC DataChannel or a HTTP/2 Stream
https://www.chromestatus.com/feature/5274139738767360#:~:text=Fetch%20upload%20streaming%20lets%20web,things%20involved%20with%20network%20requests).
Very cool video explaining the feature: https://www.youtube.com/watch?v=G9PpImUEeUA
Lots of different points here, will try to address them all.
The idea is 100% feasible. Check out Pion WebRTC's data-channels example. All it takes a single request/response to establish a connection.
Performance
Data channels are a much better fit if you are doing latency sensitive work.
With data channels you can measure backpressure. You can tell how much data has been delivered, and how much has has been queued. If the queue is getting full you know you are sending too much data. Other APIs in the browser don't give you this. There are some future APIs (WebTransport) but they aren't available yet.
Data channels allow unordered/unreliable delivery. With TCP everything you send will be delivered and in order, this issue is known as head-of-line blocking. That means if you lose a packet all subsequent packets must be delayed. An example would be if you sent 0 1 2 3, if packet 1 hasn't arrived yet 2 and 3 can't be processed yet. Data channels can be configured to give you packets as soon as they arrive.
I can't give you specific numbers on the CPU/Memory costs of running DTLS+SCTP vs TLS+WebSocket server. It depends on hardware/network you have, what the workload is etc...
Multiplexing
You can serve multiple DataChannel streams over a single WebRTC Connection (PeerConnection). You can also serve multiple PeerConnections over a single port.
Network Transport
WebRTC can be run over UDP or TCP
Load Balancing
This is harder (but not intractable) moving DTLS and SCTP sessions between servers isn't easy with existing libraries. With pion/dtls it has the support to export/resume a session. I don't know support in other libraries however.
TLS/Websocket is much easier to load balance.
End to end encryption
WebRTC has mandatory encryption. This is nice over HTTP 1.1 which might accidentally fall back to non-TLS if configured incorrectly.
If you want to route a message through the server (and not have the server see it) I don't think what protocol you use matters.
Topologies
WebRTC can be run in many different topologies. You can do P2P or Client/Server, and lots of things in between. Depending on what you are building you could build a hybrid mesh. You could create a graph of connections, and deploy servers as needed. This flexibility lets you do some interesting things.
Hopefully addressed all your points! Happy to discuss further in the comments/will keep editing the question.
I was also wondering about this HTTP-over-WebRTC DataChannel idea a couple of years ago. The problem at hand was how to securely connect from a web app to an IoT device (raspberry pi) that sits behind a firewall.
Since there was no readily available solution, I ended up building a prototype. It did the job and has been in live deployment since 2019.
See this technical blog post that covers the design and implementation in more detail:
https://webrtchacks.com/private-home-surveillance-with-the-webrtc-datachannel/
High level architecture:
Simplified sequence diagram:
Recently began the process of extracting the code into a standalone repo.
https://github.com/ambianic/peerfetch
If your main use-case exchanges small content, you may have a look at CoAP RFC 7252. A peer may easily implement both roles, client and server, though the exchanged messages for request and response share the same fomat.
For some advanced usage of DTLS 1.2, DTLS Connection ID can do some magic for you.
If you don't stick to javascript and java is an option, you may check the open source project Eclipse/Californium. That's a CoAP/DTLS implementation, which comes with DTLS Connection ID and some prepared advanced examples as built-in-cid-load-balancer-support or DTLS-graceful-restart.

How does RTCPeerConnection use the array of STUN/TURN servers?

We are doing some research regarding the behavior of Web RTC with the list of STUN/TURN servers provided. I cannot find any documentation so I am doing some tests but I hope someone can provide a clear explanation.
Following the documentation (https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer/urls) we can provide any number of servers.
But how does the RTCPeerConnection choose the server to use?
Does it try the first one and if it fails try the second one until one works?
Should all the servers be up and running or is the connection able to skip an unreachable server?
If the first server is able to conclude the negociation, does it still try with the remaining servers?
Does it simply change the list of candidates?
To provide more context, we have a working WebRTC application using the Google Stun Servers (stun.l.google.com:19302) however we are migrating on our own STUN servers. We have an API that returns the list of STUN servers to use however based on the behavior we might provide a different list.
Thanks for your help
But how does the RTCPeerConnection choose the server to use?
The RTCPeerConnection doesn't choose a server it choose a pair of ICE candidates. A ICE candidate is generated by contacting the servers.
Does it try the first one and if it fails try the second one until one works?
It contacts them all (this process is called gathering). Your WebRTC implementation may stop gathering when a connection is established.
Should all the servers be up and running or is the connection able to skip an unreachable server?
It is ok for a server to be down. Trickle ICE allows connectivity checks to proceed if all of them are not working.
If the first server is able to conclude the negociation, does it still try with the remaining servers?
Two WebRTC Agents don't communicate through a STUN server, this question has a little more nuance. In the connectivity chapter of WebRTC for the Curious check out how ICE goes through steps.
Does it simply change the list of candidates?
Yea! For each STUN server you may have another candidate. This depends on the behavior of your NAT. You could be behind a NAT configuration that only gives you one mapping. Unlikely but still possible!

User friendly way of closing node.js websocket connections

I have an application that spins up websocket connections on random ports after checking to make sure the port has not yet been assigned. Each connection has a front facing card with a slider to create/destroy the TCP connection based on the port number they are assigned (and stored). It is simple to spin up a server for each socket with the predefined event handling that it comes with but i am unsure of a way to allow the user to kill the tcp connection. What this would look like is the user from the front end woudl slide the toggle intot eh off position and I would take that entities id, query for its port number and would then need to close that port's connection. I am hoping there is a way with node to be able to query for its active servers and act on them as one pleases but I have not found any articles suggesting a way.
I am hoping there is a way with node to be able to query for its active servers and act on them as one pleases but I have not found any articles suggesting a way.
There is no such thing built into node.js.
If you wanted to be able to operate on all the webSocket servers you had started, then you could just add them to an array as you start them.
const serverArray = [];
// code elsewhere that starts a server
let server = new WebSocketServer(someRandomPort);
// push an object into an array that has the port and server
serverArray.push({server, port: someRandomPort});
Then, you could iterate over that array at any time to do something to all of them or to find a server that is using a particular port.
But, it sounds to me like you don't really need multiple webSocket servers. Multiple clients (with however much security you want) can all share the same server. That's the usual client/server design (multiple clients talking to one server).

How do I use RtcPeerConnection to connect with other instances?

I have followed the tutorials on http://www.html5rocks.com/en/tutorials/webrtc/basics as well as watch some of the videos but I am so confused. I was able to get 2 peerConnections working on a single page but I have no Idea how build on this to actually allow users on different machines/networks or what ever to actually connect.
From what I can see it involves using socket io and I have found plenty full frameworks and apps doing it but I am struggling to understand it.
Can any one point me to any tutorials that would help me to go from this rtcPeerConnection to communicating with other instances
Any help is greatly appreciated
To allow 2 users establish p2p connection, one of the peer should send "description" (ip address, port, etc) to second peer. Second peer sets it as remote description using setRemoteDescription method of RTCPeerConnection. Second peer invokes createAnswer and sends its localDescription to first peer.
When both peers know about each other, connection can be established. I think that tutorial mentioned by you in first link is comprehensive.
To allow 2 peers exchange "descriptions" you can use any hand-written signalling server. For example client can poll web-server using http.

What is the most up-to-date method of establishing multiple peer-to-peer connections using WebRTC?

Here's my current issue: I've been browsing multiple WebRTC resources, looking through Google experiments and likewise Mozilla ones too, but I have yet to find a simple explanation of how to do this. I'm also having trouble understanding the basic architecture of WebRTC.
What I would like to do is construct a peer-to-peer overlay, wherein each node is a browser. Each of these nodes would accept all incoming connections, and be able to connect to others using their IP address. They would communicate only over a DataChannel. Unlike many of the examples I have been reading, I would not like to rely on any server for signalling, only those necessary for subverting NAT (like STUN servers).
Could anyone explain how this might be achieved? I've been reading the resources on the WebRTC Experiments site and I need to do something with offers or something, but I'm not quite understanding.
How you address nodes in WebRTC is totally up to you, the implementor, because signalling is - deliberately - left out of the specification. So if you'd like to address the nodes in your overlay by their IP addresses, go ahead. But I think you slightly misunderstood how connection establishment in WebRTC works, so let me dive a bit deeper:
WebRTC connection establishment is accomplished by exchanging SDP messages (http://en.wikipedia.org/wiki/Session_Description_Protocol). If you want one browser to establish a PeerConnection to another browser, you'll have to find a way to send the SDP message (generated via RTCPeerConnection#createOffer) to the other browser. There's no way to just open a UDP connection to that browser (or ICE wouldn't work).
So for a node to join the overlay network you'll have to have a central point (let's call it server) or another channel (have a look at https://github.com/cjb/serverless-webrtc/ for "server-less" WebRTC) for connection establishment. As soon as all your nodes are connected to each other via RTCPeerConnections (e.g. as a chain) you can use those connections for further connection establishment (i.e. transfer SDP offers/answers through these connections).
Back to addressing nodes via IP address: This is not a good idea because sometimes you don't even know the address (e.g. when STUN and esp. TURN come into play).
Edit to answer question in comment:
Instead of the IP address you could use sth. like a UUID (http://en.wikipedia.org/wiki/UUID). Also, you could as well use sth. like the user's e-mail address if all your users are authenticated in some way. But keep in mind that the matter of authenticating peers is still not fully specified by IETF/W3C and implementations don't exist, yet.

Categories