Share one UDP socket with all UDP candidates
Your environment.
- Version: v0.4.3
- Browser: n/a
What did you do?
During the work of #46, I noticed that a UDP socket was created for each 3 types of initial candidates, host, srflx and relay.
What did you expect?
All candidates (in the same address family) should share the base UDP socket (used for host candidate)
Current socket allocation:
(udp soc 1) --------------- host candidate (192.168.1.2:5000)
(udp soc 2) --------------- srflx candidate (27.1.1.1:49152 related 192.168.1.2:5001)
(udp soc 3) --------------- relay candidate (1.2.3.4:5678 related 192.168.1.2:5002)
25 candidate pairs (or pings per period)
soc1 and 3 would create NAT binding, and these could be detected as prflx candidates.
Ideal socket allocation:
(udp soc 1) -------+------- host candidate (192.168.1.2:5000)
+------- srflx candidate (27.1.1.1:49152 related 192.168.1.2:5000)
+------- relay candidate (1.2.3.4:5678 related 192.168.1.2:5000)
9 candidate pairs (or pings per period)
What happened?
- Wasteful socket resource usage
- Wasteful pings (connectivity checks)
- Debug is hard.
Incoming packages should be demux/parsed like this:
In order to make this possible, we will need to modify pion/stun and pion/turnc to use net.UDPConn which is not bound to a specific remote address, meaning, we should use net.ListenPacket(or net.ListenUDP). NOT net.DialUDP! (it creates a "connected" udp socket!)
Here's a demo
The new TURN Client (in pion/turn) is ~almost~ ready. (see pion/turn#75).
The new client will allow achieving what this PR is aiming for, but let's do it after pion/webrtc#712 successfully lands. (This does not strictly affect connectivity)
Here's what we need to do...
Since currently, all Candidate (concrete) classes share the parent (or embedded in a go's sense) struct, candidateBase which invokes a read-loop (goroutine) on start() - this needs to be changed.
Here's my plan:
- Create a candidateBase per local IP address
- candidataBase also has an instance of turn.Client.
- Let candidateBase creates actuall candidates such as CandidateHost, CandidateServerReflexive, etc. In another word, candidataBase works as a "candidate factory". For instance, candidateBase would have these methods:
- createCandidateHost()
- createCandidateSrflx()
- createCandidatePrflx()
- createCandidateRelay()
- When createCandidateRelay() is called, candidateBase also allocates a relay port on the TURN server.
At this point, we will have a proper STUN transaction (and with retransmits) with STUN server, as well as connectivity checking all done by the new turn.Client.