agent: eliminate redundant candidates
The patch is intended to process or ignore some redundant candidates according to RFC 8445 section 5.1.3. It will reduce unnecessary checks and fix unexpected behavior of local candidates matching algorithm that leads to #180.
I was able to consistently reproduce local candidates matching logic issue with the following scenario:
-
L
is controlling ice agent,R
is controlled ice agent; -
L
andR
start local candidates gathering. Let's say thatL
agent has 1 local candidate —A(type = host)
andR
agent has 2 —B(type = host)
,C(type = server-reflexive)
; -
R
agent sends two candidates through signaling channel to agentL
. The difference of candidates is comprised in their type and their priority, ip-addresses and ports of candidates are equal. The first candidate is server-reflexive, the second one is host. Priority of server-reflexive candidate is higher than priority of host candidate; -
L
agent creates two check-pairsA:B
andA:C
; -
L
agent sends two stun binding requests toR
agent respectively; -
L
agent receives first binding response for pairA(type=host):C(type=server-reflexive)
, which new state isSUCCEDED
; -
L
agent receives second binding request for pairA(type=host):B(type=host)
, which new state isSUCCEDED
, but due to unexpected local candidates matching algorithm behavior, candidateC
is considered local candidate for received response and pairA(type=host):C(type=server-reflexive)
state becomesDISCOVERED
; - Agent L tries to nominate pair
A(type=host):C(type=server-reflexive)
because the priority of server reflexive candidate is higher. In that case, agentL
fails at assertion because state of this pair isDISCOVERED
!=SUCCEDED
which leads to issue #180.
Candidate C
is considered local, that matches stun-binding-response, because libnice is trying to find matching local candidate using algorithm conncheck.c 4721-4735. In simple words, this algorithm takes listening socket address and then takes first local matching candidate with the same address and transport type. Since, we have two candidates with the same address and transport type, it's undefined which one would be selected.
According to RFC 8445 section 5.1.3. such candidates as B
should be considered redundant and ignored, due to same address and lower priority. In case, if the redundant candidates are ignored, the matching algorithm described earlier will work as expected
Fixes: #180