Is WebRTC without createOffer/Answer possible on a local network? - javascript

Is it possible to establish a WebRTC connection between two browsers on a local area network without calling createOffer/Answer and instead by manually creating local and remote descriptions?
The browsers are not behind NAT with respect to each other and they have signaled their IP addresses somehow (say via a local HTTP server).
Would it be possible to do something in the spirit of:
const myIp = '192.168.0.1';
const peerIp = '192.168.0.2';
const c = new RTCPeerConnection();
c.setLocalDescription(MAGIC_createLocalDescriptionFor(myIp));
c.setRemoteDescription(MAGIC_createRemoteDescriptionFor(peerIp));

Yes! If you are using Chrome. Check out offline-browser-communication
You have three points of state you need to deal with.
IP/Port. You can setup your network in a way that this is stable. Or attempt to do some guessing?
ufrag/pwd. You can set this via SetLocalDescription so you can control these.
DTLS Certificate. Use GenerateCertificate this means you will only have to signal it once.

Not in the browser. The offer and answer contain properties such as ice-ufrag, ice-pwd, the DTLS fingerprints and the candidate ports etc that are not static.

Related

js-ipfs connect two browser peers

I have 2 devices (desktop PCs), each running a browser tab that instantiates an IPFS node using js-ipfs.
//file index.html, served over HTTPS
const node = IpfsCore.create(); //ipfs browser node
Both nodes have peers (calling node.swarm.addrs() returns about 50 peers). They do not list each other as peers.
I want to connect those two nodes to each other, so if I call node.add( ... ) on the first, I can then call node.cat( ... ) on the second, and acquire a file from the first. (Or so that browser 1's pubsub broadcasts always reach browser 2; browser 1 can read browser 2's wantlist etc.)
How do I connect these 2 browser tabs as peers?
The example at https://github.com/ipfs/js-ipfs/blob/master/packages/interface-ipfs-core/src/swarm/connect.js uses this command:
ipfsA.swarm.connect( ipfsBId.addresses[0] )
But in my case, both my browser-tabs have no addresses.
console.log( ( await node.id() ).addresses ); //[] empty array
I don't know how the browser tabs manage connecting to other peers without their own addresses, and I don't know how to make them connect to each other.
There is a 4-year-old question about browser peers here IPFS - pubsub connect to peers from browser, but its fairly unrelated and seems to rely on the the deprecated / out-of-date webrtc-star https://github.com/libp2p/js-libp2p-webrtc-star
I know if I were setting up a WebRTC connection I would use fetch() or XHR or a websocket to a public-facing server (with a DNS record or IP address) to exchange negotiation info while querying a list of iceServers (also with DNS records / IP addresses).
I don't want to rely on a list of servers I own or configure, and I don't want to burden any public example TURN servers or anything. js-libp2p might use multicastDNS? I don't think browser tabs can broadcast signals though (I could be wrong? Maybe fetch() can do that somehow with some sneaky url stuff?)
What do I do? How can these two browser-tab IPFS peers discover each other, specifically?
I suspect this has a very straight-forward answer, but I have been researching for days now and read hundreds of pages, and none of the documentation I have read anywhere is relevant. Wherever the answer is on this vast Internet, I have not been able to find it.

Socket in javascript

please what is different
var socket = new WebSocket('ws://localhost:8181');
var socket = new WebSocket('ws://localhost:8181/websession');
what is ( Websession )
websession is just the endpoint the websocket will connect to. It's just like normal HTTP servers or REST services: You can have multiple endpoints on one server, like:
ws://localhost:8181/customers
ws://localhost:8181/prices
ws://localhost:8181/items
... and so on. (This is just an example and does not necessarily make sense for a specific use case.) In old-style HTTP, you could image them as different directories on the same server, possibly offering very different contents.
In order to use the socket correctly, you have to know your desired endpoint and use it when creating the socket. So it depends on the server whether ws://localhost:8181 or ws://localhost:8181/websession is correct (or even both of them, depending on the purpose of the individual endpoint). It's generally a good practice to give the endpoint a meaningful name, so the first one would be discouraged.
As the application seems to be running on your localhost, you should take a look at the server running at port 8181 to find out the endpoints offered. And you could possibly get used to websockets, here is one of many possible starting points.

WebRTC on shared hosting ( SSH ) without nodejs, preferrably in php

So ive been looking for a way to integrate webRTC into a site im making, but i want to do it on shared hosting. I came across this repo on GitHub by nielsbaloe and it has been a huge help in getting a basic connection.
This is the code i believe is responsible for adding the peer: ( index.html in the repo, line )
function icecandidate(localStream) {
pc = new RTCPeerConnection(configuration);
pc.onicecandidate = function (event) {
if (event.candidate) {
publish('client-candidate', event.candidate);
}
};
try {
pc.addStream(localStream);
}catch(e){
var tracks = localStream.getTracks();
for(var i=0;i<tracks.length;i++){
pc.addTrack(tracks[i], localStream);
}
}
pc.ontrack = function (e) {
document.getElementById('remoteVideo').style.display="block";
document.getElementById('localVideo').style.display="none";
remoteVideo.srcObject = e.streams[0];
};
}
Now the struggle im facing is adding room functionality, and maybe the ability to have more than two concurrent peers present at the same time. I did some experimenting, but in vain. I know that for room functionality id have to tinker around in the php, so at least id like to figure out how to make more than 1 peer possible.
As far as I know, there is no way to re-use the same RTCPeerConnection for multiple peers, so you'll have to do the same thing as 1-on-1 but between every single peerĀ in a group.
As far as signalling, it's pretty simple, goes kind of like this:
Client A -> [Offer] -> Server -> [Offer] -> Client B -> [Answer] -> Server -> [Answer] -> Client A
A nicer explanation at MDN
There isn't necessarily a need for NodeJS or WebSocket. The reason most people go for it it is because the last link in this chain (Server -> Client A) requires server-initiated connection. But that can be substituted with alternative techniques such as (long-)polling. Or, in case of PHP, you might use websocket implementations such as Bloatless or Aerys
To implement the room functionality, you'll have to implement the following:
Variant A (using polling):
An endpoint to throw offers at, e.g. POST /rooms/{id}
An endpoint to regularly check for new offers from, e.g. GET /rooms/{id}
Variant B (with websockets)
Create a broadcast rooms, for example, by dynamically creating HTTP endpoints and websocket server instances. Or by having a single websocket instance but sending whatever room you're intending to join right inside after establishing a connection. From there, it's only a matter of sending correct offers and answers to correct users.
In both cases, you might want to either create multiple offers in advance to pool from the server, or to dynamically create new ones, but, most importantly, make sure you're not connecting the same peers twice, otherwise you will end up with a loop. To prevent it, just provide each user with a randomly generated string to identify themself and send it among offers.
There are turnkey solutions available if you don't want to go this route, but be careful and check whether you can use your own TURN servers with them. A common trend I have noticed is that there are a lot of WebRTC solution providers out there that lure you with their simplicity but then lock you in with their own TURN servers for which you might have to pay a quite hefty bill later on.

Is it possible to convert a WebRTC SDP offer to answer?

I have two peers that want to connect to each other via WebRTC. Typically the first peer would create an offer and send it to the second via a signalling channel/server, the second peer would respond with an answer. This scenario works fine.
However, is it possible to support the case where both peers happen to try to connect to each other simultaneously both sending SDP offers to one another concurrently via the signalling server.
// Both peers do this simultaneously:
const conn = new RTCPeerConnection(null);
const sdpOffer = await conn.createOffer();
await conn.setLocalDescription(sdpOffer);
signalingService.send(peerId, sdpOffer);
// At some point in the future both peers also receive an SDP offer
// (rather than answer) from the other peer whom they sent an offer to
// via the signaling service. If this was an answer we'd call
// RTCPeerConnection.setRemoteDescription, however this doesn't work for an
// offer:
conn.setRemoteDescription(peerSDPOffer);
// In Chrome results in "DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer"
I even tried to "convert" the received peer offers into answers by rewriting the SDP type from offer to answer and setup:actpass to setup:active but that doesn't seem to work, instead I just get a new exception.
So the question is, is this simultaneous connect/offer use case supported in some fashion - or should I close one side/peer RTCPeerConnection & instantiate a new one using RTCPeerConnection.createAnswer this time?
This situation is known as "signaling glare". The WebRTC API does not really define how to handle this (except for something called "rollback" but it is not implemented in any browser yet and nobody has missed it so far) so you have to avoid this situation yourself.
Simply replacing the a=setup won't work since the underlying DTLS mechanism still needs the concept of a client and a server.
The answer for how to avoid glare these days is to use the Perfect Negotiation Pattern: https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Perfect_negotiation
However, what OP described does work with the slight modification of setting setup:active on one peer and setup:passive on the other:
https://codepen.io/evan-brass/pen/mdpgWGG?editors=0010
It might not work for audio / video connections (because those may require negotiating codecs), but I've tested it on Chrome / Firefox / Safari for DataChannel only connections.
You could choose which peer is active and which is passive using whatever system you use to determine 'politeness' in perfect negotiation. One possibility would be to compare the DTLS fingerprints and make whichever one is larger the active peer.

Nodejs + Socket.IO - how to get total bytes transferred (read/write) after socket close

I have a simple socket.io client and server program, running on node.js. The client and server exchange messages between them for a few minutes, before disconnecting (like chat).
If there any function/method I can use to get the total bytes transferred (read/write), after the socket is closed?
At present I am adding up the message size for each each message sent and received by the client. But, as per my understanding, in socket.io depending on which protocol is used (websocket, xhr-polling, etc.), the size of the final payload being sent will differ due to the header/wrapper size. Hence, just adding message bytes won't give me an accurate measure of bytes transferred.
I can use monitoring tools like Wireshark to get this value, but I would prefer using a javascript utility to get this value. Search online, didn't give me any reasonable answer.
For pure websocket connections, I am being able to get this value using the functions: socket._socket.bytesRead and socket._socket.bytesWritten
Any help is appreciated!
As of socket v2.2.0 i managed to get byte data like this. Only problem these are specified when client closes browser window and reason parameter is transport error. If client uses socket.close() or .disconnect() or server uses .disconnect() then bytes are 0.
socket.on('disconnect', (reason) => {
let symbs = Object.getOwnPropertySymbols(socket.conn.transport.socket._socket);
let bytesRead = socket.conn.transport.socket._socket[symbs[3]];
let bytesWritten = socket.conn.transport.socket._socket[symbs[4]];
});
If you wanted such a feature that would work no matter what the underlying transport was below a socket.io connection, then this would have to be a fundamental feature of socket.io because only it knows the details of what it's doing with each transport and protocol.
But, socket.io does not have this feature built in for the various transports that it could use. I would conclude that if you're going to use the socket.io interface to abstract out the specific protocol and implementation on top of that protocol, then you give up the ability to know exactly how many bytes socket.io chooses to use in order to implement the connection on its chosen transport.
There are likely debug APIs (probably only available to browser extensions, not standard web pages) that can give you access to some of the page-wide info you see in the Chrome debugger so that might be an option to investigate. See the info for chrome.devtools.network if you want more info.

Categories

Resources