I've written a small WebRTC demo that streams a video file to the other peer and everything works fine (it's a real P2P connection without using the TURN server) except for this:
One client connects via a mobile network and one via wifi. When the mobile client creates the offer and kicks off the ICE candidate back-and-forth, they settle on srflx candidates and create a real P2P connection.
But when the wifi-client creates the offer, they fall back to the TURN server as a relay.
This happens in Firefox and Chromium on Ubuntu.
Does this behavior point to an obvious problem in my code?
If not, how can this be? Shouldn't the ICE protocol produce the same two candidates no matter which client is the controller?
NATs have two attributes influence if a connection will succeed between two WebRTC Agents. Those attributes are filtering and mapping.
When you send a packet to an address outside your NAT you create a mapping. A mapping is your IP:Port and people usually call it your Public IP. This is the Public IP that others can send into. A STUN server is just an echo server that responds with your mapping.
The first mapping type is an Address Independent NAT. This is the one you want. In this configuration you re-use a mapping everytime you contact an IP outside your NAT. You can give out your mapping to remote peers and they can send to you.
The second mapping type is Address Dependent. In this configuration you create a new mapping for each remote address. This means that the IP/Port you got back from the STUN server can NOT be used by other peers. In this case you may have to use a TURN server.
filtering controls who is allowed to send in. Some NATs allow anyone to send traffic in. Like mapping behavior this is called Address Independent. Other NATs only allow someone to send traffic in that you have attempted to contact, knows as a Address Dependent NAT.
Check out WebRTC for the Curious's Connecting Chapter I try to explain this in more depth. Pion also has a tool stun-nat-behavior that prints out the details of your NAT like so.
connecting to STUN server: stun.voip.blackberry.com:3478
=> NAT mapping behavior: endpoint independent
=> NAT filtering behavior: address and port dependent
Related
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!
Recently i've been choosen as backend lider for course on my studies. We are suppossed to write BE for chat app that will allow users to communicate p2p without any server code (i know it means that there's no BE, but my proffessor isn't technical person). I've asked him if it could use webrtc, but he didn't like the idea of using STUN and TURN servers. So my main question is, is this possible at all? We are talking about an app that will run in browser, not directly in OS. And if it is, what protocols/apis can we use to achieve that?
I am not sure if I get your question right, so here are some general informations:
WebRTC as a P2P API relies heavily on servers.
"ICE":
To connect one Peer to the other Peer, the peers need to know their IP address to exchange data. They can "ask" their OS for the registered IP, but this will only yield 127.0.0.1 and their local Network IP. This works for connections on the same computer or between computers in the same local network, but it will fail for everything else.
The ICE Servers STUN and TURN are necessary, since your browser clients are behind your Routers Network Address Translation (NAT). STUN gets the NATs IP Address and Port and TURN forwards Packets as a known, public IP Address if STUN fails.
"Signaling":
Let's assume, that your Peers know their own reachable IP-Addresses (- probably the NATs IP and Port by using STUN and maybe even TURN). Even IF (!) they know their reachable IP, they have to tell the other Peer that this IP is in fact, their IP and the IP to use to contact them. They also have to tell the other Peer some other technical information to make the transmission of data work. To use WebRTC, you need to have a WebSocket-Server (or a combination of Server-Sent-Events and HTTP Post Messages), which forward this information.
After everything is established (they know their respective IPs and Ports, technical information, etc.), you can then send data over WebRTCs DataChannels.
My Advice:
Do not use WebRTC for the given use case. If you do not want to use a Backend-Server, you have to search for "serverless" Web-Apps. P2P will always rely on some sort of server to start the connection. If you use a "serverless" architecture, someone else is hosting the server / chat service you want to use (also commonly referred as "cloud based"). If it is about hosting costs for a prototype app, you may have a look at heroku.com, aws.amazon.com, zeit.co, firebase.google.com or other hosting providers with free, limited (test) plans.
WebRTC signalling is driving me crazy. My use-case is quite simple: a bidirectional audio intercom between a kiosk and to a control room webapp. Both computers are on the same network. Neither has internet access, all machines have known static IPs.
Everything I read wants me to use STUN/TURN/ICE servers. The acronyms for this is endless, contributing to my migraine but if this were a standard application, I'd just open a port, tell the other client about it (I can do this via the webapp if I need to) and have the other connect.
Can I do this with WebRTC? Without running a dozen signalling servers?
For the sake of examples, how would you connect a browser running on 192.168.0.101 to one running on 192.168.0.102?
STUN/TURN is different from signaling.
STUN/TURN in WebRTC are used to gather ICE candidates. Signaling is used to transmit between these two PCs the session description (offer and answer).
You can use free STUN server (like stun.l.google.com or stun.services.mozilla.org). There are also free TURN servers, but not too many (these are resource expensive). One is numb.vigenie.ca.
Now there's no signaling server, because these are custom and can be done in many ways. Here's an article that I wrote. I ended up using Stomp now on client side and Spring on server side.
I guess you can tamper with SDP and inject the ICE candidates statically, but you'll still need to exchange SDP (and that's dinamycally generated each session) between these two PCs somehow. Even though, taking into account that the configuration will not change, I guess you can exchange it once (through the means of copy-paste :) ), stored it somewhere and use it every time.
If your end-points have static IPs then you can ignore STUN, TURN and ICE, which are just power-tools to drill holes in firewalls. Most people aren't that lucky.
Due to how WebRTC is structured, end-points do need a way to exchange call setup information (SDP) like media ports and key information ahead of time. How you get that information from A to B and back to A, is entirely up to you ("signaling server" is just a fancy word for this), but most people use something like a web socket server, the tic-tac-toe of client-initiated communication.
I think the simplest way to make this work on a private network without an internet connection is to install a basic web socket server on one of the machines.
As an example I recommend the very simple https://github.com/emannion/webrtc-web-socket which worked on my private network without an internet connection.
Follow the instructions to install the web socket server on e.g. 192.168.1.101, then have both end-points connect to 192.168.0.101:1337 with Chrome or Firefox. Share camera on both ends in the basic demo web UI, and hit Connect and you should be good to go.
If you need to do this entirely without any server, then this answer to a related question at least highlights the information you'd need to send across (in a cut'n'paste demo).
I'm using an arduino UNO and an Ethernet Shield to create a web server to response HTTP requests.
The requests are sent by ajax XMLHttpRequest.
It's working fine with static ip address.
But a want the arduindo to get a DHCP ip, so I can use it in any local network (with DHCP).
I want to discover the ip of the arduino connected on the local network.
So I can use it as url to send HTTP requests.
Is it possible to do that in javascript?
OK, thanks for answering my questions above. That helped layout the network structure and the problem you're trying to solve.
Summary of the problem
Two computers: 1 web server whose address is dynamic (DHCP) and 1 web client running AJAX and HTML. How can browser find DHCP server?
Options
This is a classic problem solved many different ways throughout the history of computer networks. I've suggested some options below.
Scan for the server via TCP.
Scan for the server via UDP (requires special browser library).
Run a DNS server.
Have Arduino signal its IP.
Modify your router.
Don't run DHCP - use a static IP.
tl;dr - Use Option 6 if you don't control your router, Option 5 if you do.
Option: Scan for the server
I'm assuming you know your browser machine's IP address (for example, 192.168.1.17). In this case, run through all of the address from 192.168.1.0 through 192.168.1.254 (not .255 and skip you browser machine's IP) testing for a connection to port 80. This will find every web server on your subnet, so be aware you will need a way to recognize your arduino responded to the web request in case some other web server is also listening on the network. It will also take some time to set up, test and wait for timeouts on most (252) of the addresses which don't have web servers. You will eventually find it.
I'm not a fan of this one, but it gets the job done. Warning: if you don't "own" the network, someone may be angry with you for scanning their machines. A company, school or other institution may have policies about not scanning networks.
Option: UDP from the browser
This one is great, but requires a browser plug-in and some fancy coding. UDP allows one to broadcast a message to your subnet (try ping 255.255.255.255 at a command line and watch the machines echo back their IPs). If the arduino is set to listen for UDP packets on a particular port, it can echo back to the sender of the UDP packet and let that user know it's present. This is how DNS, DHCP, ping and Apple's Bonjour work. Many IP based systems advertise services by responding to UDP requests. Clients need not know the address of the servers on the subnet, they discover them through broadcast messages on well-known UDP ports.
Unfortunately, this requires a browser modification because Javascript does not support UDP for security reasons. I understand this and agree with the security restriction. However, it has cut out a really nice feature of dynamic service discovery. If you're on Apple on the browser, you might be able to find a Bonjour emulator you can run on the Arduino and it might work ("arduino.local" might attach). This might be possible with Windows service discovery, too, if you're using a Windows client for your browser. I don't know what's available in Linux for service discovery.
I don't like any of these modifications for you. Browser, Arduino (Apple, Windows or Linux), just because it adds more moving parts and you're counting on the browser to "know" how to find the service.
Option: Run a DNS server
This isn't as bad as it sounds, but I'm not sure the Arduino could handle it. Find a very small DNS server written for the Arduino and have it respond to DNS requests. On the browser, look for a well-known machine name (e.g. "my-arduino.lan"). This essentially finesses the UDP problem above by making the Arduino the UDP server (handles DNS requests) and the browser already has name resolution s/w (like every machine on the planet).
I didn't search for Arduino DNS code, it might be too large for the Arduino and writing it may be a real PITA (pain in the butt).
Option: Arduino signals IP
In this model, you can attach a LCD to the arduino and have it present its IP address on the display. Alternatively, the arduino can send a message (via TCP) to a well known server on the network (internet or otherwise) reporting its IP address there. Your browser can query that server, pick up the IP address and then contact the Arduino directly. This introduces a 3rd machine and acts like your own hacked form of DDNS (look it up, if you're not familiar with it).
Option: Modify the router
If you own the router, you can modify the router to assign a specific IP address to the Arduino, even with DHCP. This is your best bet. Here, you control the network, can allow the Arduino to come up in DHCP while still fixing its IP address. You'll have to go through your router API (web or CLI) and figure out how to do it, it's a bit hard directing you as there are thousands of types of commercial and SOHO routers.
If you don't control the router...
Option: Use Static IP
This option is really your best. Give up on DHCP and just set the static IP of the arduino. Just make sure the IP address you pick doesn't conflict with any other servers on the subnet. That shouldn't be difficult.
I hope this helps.
The 2 best options I think:
1) When arduino starts, gets an IP address from DHCP, arduino should make a connection to a well know service provided by you. Also, each device should have an ID, defined by you during manufacturing, like mac address or part of mac address.
So, you can print on the box something like: 5c4e6f.my-well-know-host.com
Than, as I was suggesting, each time arduino starts, it tries to connect to that service passing parameters like:
POST www.my-well-know-host.com
ID: 5c4e6f
IP: 192.168.1.55
than, at that service, you update a DNS table to reflect this relation:
5c4e6f.my-well-know-host.com -> resolves to 192.168.1.55
obviously, from anywhere in the world the host 5c4e6f.my-well-know-host.com will resolve to 192.168.1.55, but you will only access it from you local network.
Tip: this is some kind of DDNS, but with network discovery purposes.
Tip2: there is an linux dns service called MyDNS, where the hosts are simply records inside a MySQL table, easy to maintain.
2) Network discovery
I don't know if arduino is capable to do it, but, the idea is to make arduino listen on a specific UDP port, like 4444, on any address.
So, you can build a windows app, and Android APP (I already made one android discovery for another purpose, not arduino), or, the best solution that I still researching on, is to make a custom page with some javascript code, that "looks" for devices listening on that specific port.
Works like that:
Device gets IP from DHCP
device starts a thread listening for broadcast packets on port 4444
a discovery app listen on another port, like 4445.
the discovery app announces itself using a broadcast packet to 4444 port (255.255.255.255:4444)
each device listening, reports back with its identification and IP to app port 4445.
This is a code to find the server ip:
<script type="text/javascript">
var ip = "<?php echo $_SERVER['SERVER_ADDR']; ?>";
alert(ip);
</script>
If you are using Johnny Five framework, then you can find APIs in that framework
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.