Subject: [MMUSIC] Trickle ICE and frozen candidates

From: Emil Ivov <[email-masked]>
Date: Tue, 09 Jul 2013 14:44:05 +0200

Hey all,

In Orlando we discussed a few issues around trickle ICE without reaching 
any form of consensus so it would be great if we could do so here.

The most delicate is about handling frozen candidates with trickle ICE. 
I apologise for the long e-mail that's about to follow. It's just one of 
those gluey, hairy issues. The faster we get rid of it, the better, so 
please don't be intimidated by the text ;).

With vanilla ICE, we have the advantage of knowing that candidate pairs 
will be ordered the same way on both sides. Checks are executed in the 
same order, which allows NATs to open all the necessary holes in their 
filters.

The "frozen candidates" algorithm relies on this. It starts by 
unfreezing, on both sides, all the first pairs for all foundations. In 
other words, for an audio/video rtp/rtcp call, we normally start ICE 
processing with Audio.RTP and then unfreeze RTCP and Video when the 
first checks have succeeded (roughly put).

The problem with trickle ICE is that such an order is no longer 
guaranteed. It is hence possible that both agents obtain their STUN 
candidates in different order. For example, one of them first obtains 
Audio.RTP, while the other one first learns a mapping for Video RTCP.

Here's a more specific example: Imagine Alice and Bob both have a single 
host address each: A1 and B1 (both are NATed in different LANs). They 
both use ports 5000/5001 for Audio RTP/RTCP and ports 5002/5004 for 
Video RTP/RTCP.  They also both use a STUN server (no TURN for simplicity).

Now let's say that Alice gets (and trickles) a STUN candidate for her 
Audio.RTP base, while Bob first obtains one for RTCP.

For clarity, their check lists would hence look something like this:

Foundation:  A1B1	       A1B2	        A2B1	
Audio.RTP    A1:5000/B1:5000                    A2:5000/B1:5000	
Audio.RTCP   A1:5001/B1:5001   A1:5001/B2:5001		
				
Video.RTP    A1:5002/B1:5002			
Video.RTCP   A1:5003/B1:5003			

We now arrive at the essence: If we are to use freezing in a way that's 
similar to 5245, then Alice and Bob would both unfreeze the first pair 
they have for a given foundation and keep everyone else frozen: Alice 
will thus be sending STUN checks to Bob for Audio.RTCP, while Bob tries 
to conn. check Alice's Audio.RTP candidate.

While they do this, they will learn and trickle all the other candidates 
for these foundations but this wouldn't matter as they would have to 
remain frozen.

Both of the above checks and their entire foundations will hence fail 
since they won't be symmetric.

I hope the description makes sense.

So we basically have two ways to go about this:

1. Try to come up with some rules that avoid or fix the above situation. 
We could try to formulate text that basically starts the unfreezing only 
once we have symmetric candidates for all foundations.

2. We could start by unfreezing the first available pair for any 
foundation and then also unfreeze new pairs with a higher priority. New 
pairs with a lower priority will remain frozen until at least one higher 
priority pair succeeds.

3. We could also get rid of freezing and just start checks for anything 
we get. STUN transactions give us quite some leash in terms of time so 
that even if one of the peers starts checks for a given component 
earlier than the other, this should not be reason enough for failure. 
(Although it could lead to delays in some cases).

While 1 and especially 2 may be preferable in terms of efficiency, 
personally, I am worried that getting it right in terms of spec and 
implementation is non-trivial and this may become a common reason for 
interoperability problems. Therefore, 3 does seem like the simplest way 
to go.

Opinions?

Cheers,
Emil

-- 
https://jitsi.org

---

From: Martin Thomson <[email-masked]>
Date: Tue, 9 Jul 2013 12:45:44 -0700

On 9 July 2013 05:44, Emil Ivov <[email-masked]> wrote:
> interoperability problems. Therefore, 3 does seem like the simplest way to
> go.

You are going to want to ensure that both peers check in the same
order.  3 seems a little too loose for me.  I think that some sort of
mechanism is going to be needed to avoid problems with races, since
both peers will have different sets of candidate pairs at every point
in the process.  And signaling is slow enough for this to be a real
problem.

---

From: Emil Ivov <[email-masked]>
Date: Wed, 10 Jul 2013 03:58:26 +0200

Hey Martin,

On 09.07.13, 21:45, Martin Thomson wrote:
> order.

What exactly do you mean by "in the same order"? Do you mean that:

a) they should try and make sure that they are checking the candidate 
pair that is symmetric to the one their peer is testing and
b) all other components for the involved foundations should be frozen?

Do you have a better wording?

> 3 seems a little too loose for me.

It is indeed loose but I can't think of a reason why it wouldn't work 
even with several seconds of RTT. So, unless you are going to manually 
paste every new candidate into a mail and then do the the same on the 
remote side, you should probably be fine.

Ekr, I believe you mentioned you were doing this in Firefox? How is it 
working?

> I think that some sort of
> in the process.

OK. Do you mean something like 2. or do you have another mechanism in mind?

Emil

-- 
https://jitsi.org

---

From: Martin Thomson <[email-masked]>
Date: Wed, 10 Jul 2013 09:50:18 -0700

> OK. Do you mean something like 2. or do you have another mechanism in mind?

I don't have any particular mechanism in mind, though 2 might be
workable (I initially read "priority" there, which isn't quite right,
I think that you mean something like "preference order", since it's
the component ordering that would matter).

---

From: Emil Ivov <[email-masked]>
Date: Sat, 13 Jul 2013 02:15:26 +0200

Hey Martin, all,

> the component ordering that would matter).

Yes and the idea was that component ordering is generally the only thing 
that would influence "priority" within a single foundation. That said, I 
agree there's no reason not to say this directly.

So to summarize. The algorithm would look like this:

We start by unfreezing the first available pair for a foundation. Any 
new pairs would be:

a) automatically unfrozen if they belong to a component that precedes 
that of an unfrozen pair.

b) automatically unfrozen if other checks in that foundation already 
succeeded

c) kept frozen and then handled by regular 5245 unfreezing if they 
belong to components that come after the last currently unfrozen but not 
yet completed check

d) kept frozen if checks for unfrozen pairs in this same foundation have 
already failed.

Obviously "d" is kind of murky. We need it in order for the freezing 
algorithm to have any sense but it could still lead to race conditions 
and premature failures.

So, at least now this doesn't seem like a great way to go forward.

Therefore, it seems to me that the only way to keep "freezing" is to 
mandate that candidates be trickled by component order. This way we 
would be able to pretty much reuse the vanilla ICE algorithm.

Thoughts?

Emil

-- 
https://jitsi.org