Subject: [Wish] How to distinguish ICE restarts from candidates?

From: Juliusz Chroboczek <[email-masked]>
Date: Fri, 05 Nov 2021 13:28:15 +0100

Dear Sergio, dear all,

I still don't understand how the server can distinguish between an ICE
restart and an ICE candidate in the presence of reordering.

Suppose the client sends the following:

  Initial offer, ufrag=0
  ICE restart, ufrag=1
  ICE candidate, ufrag=1
  ICE restart, ufrag=2
  ICE candidate, ufrag=2

Suppose now that the requests get reordered, so the server gets

  Initial offer, ufrag=0
  ICE restart, ufrag=2
  ???, ufrag=1

How does the server determine whether the ufrag=1 message is an ICE
restart or an ICE candidate?  And if it's a reordered ICE restart, how
does it know to ignore it?

It looks to me like we need to explicitly forbid reordering of ICE restarts.
In that case, the previous situation cannot happen, but we can still get

  Initial offer, ufrag=0
  ICE restart, ufrag=1
  ICE restart, ufrag=2
  ???, ufrag=1

In order to determine that the last message is a reordered ICE candidate,
the server needs to maintain an unbounded history of ufrags.  This seems
fragile to me; it's especially annoying since the client knows it's doing
an ICE restart, so it might as well signal this information explicitly to
the server.

I see the following solutions:

1. Reordering is forbidden, the client must ensure it only sends
   candidates for the most recent ufrag.  This is fragile and error-prone.

2. We require the client to send a full SDP in order to perform an ICE
   restart.  In that case, we need to specify how the server reacts if the
   client changes SDP parameters (for example, what happens if the client
   attempts to change the simulcat envelope).

3. We put something in the request that allows us to distinguish without
   parsing the SDP.  We could use the Content-Type header, or we could use
   a custom HTTP header, or we coud use a URL parameter.

4. Other ideas?

My current favourite is requiring a custom HTTP header, but I'm quite
willing to implement something else.

-- Juliusz

---

From: Lorenzo Miniero <[email-masked]>
Date: Fri, 5 Nov 2021 13:38:27 +0100

On Fri, 05 Nov 2021 13:28:15 +0100
Juliusz Chroboczek <[email-masked]> wrote:

> It looks to me like we need to explicitly forbid reordering of ICE
> restarts. In that case, the previous situation cannot happen, but we
> can still get
> 
>   Initial offer, ufrag=0
>   ICE restart, ufrag=1
>   ICE restart, ufrag=2
>   ???, ufrag=1
> 
> In order to determine that the last message is a reordered ICE
> candidate, the server needs to maintain an unbounded history of
> ufrags.  This seems fragile to me; it's especially annoying since the
> client knows it's doing an ICE restart, so it might as well signal
> this information explicitly to the server.
> 
>    restart.  In that case, we need to specify how the server reacts
> if the client changes SDP parameters (for example, what happens if
> the client attempts to change the simulcat envelope).
> 
> 3. We put something in the request that allows us to distinguish
> without parsing the SDP.  We could use the Content-Type header, or we
> could use a custom HTTP header, or we coud use a URL parameter.
> 
> 4. Other ideas?
> 

I agree that it's quite fragile as it currently is, even though in
practice it shouldn't happen that often. A simple approach may be
relying on some versioning information, a bit like the SDP version: if
we increment that at each PATCH request we send, that gives the server
information to perform reordering as needed (and possibly waiting for
messages it hasn't received/processed yet).

Lorenzo

-- 
I'm getting older but, unlike whisky, I'm not getting any better
https://twitter.com/elminiero

---

From: Juliusz Chroboczek <[email-masked]>
Date: Fri, 05 Nov 2021 14:11:48 +0100

> messages it hasn't received/processed yet).

I think that if we do that, then we might as well forbid reordering.
Consider the following.

Client sends initial offer and starts ICE gathering.  The ICE gatherer is
producing candidates, which the client trickles to the server:

  Offer, seqno = 0, ufrag = A
  Candidate, seqno = 1, ufrag = A
  Candidate, seqno = 2, ufrag = A

Client does an ICE restart, and sends the restart to the server.

  Restart, seqno = 3, ufrag = B

At this point, the ICE gatherer produces a candidate for the first ufrag:

  Candidate, ufrag = A

Obviously, the client cannot send the candidate to the server, since
there's no holes in the seqno space; hence, the client must drop the
candidate.  But then, if the candidate is being dropped by the client,
there's no reordering, right?  So we might as well forbid reordering.

-- Juliusz

---

From: Juliusz Chroboczek <[email-masked]>
Date: Fri, 05 Nov 2021 14:15:03 +0100

> there's no reordering, right?  So we might as well forbid reordering.

Just to be clear: I'm not advocating we forbid reordering.  I'm advocating
that we explicity label each PATCH to indicate whether its type.

-- Juliusz

---

From: Sergio Garcia Murillo <[email-masked]>
Date: Fri, 5 Nov 2021 14:19:11 +0100

That won't solve the situation either, as the ice restart may be delayed
and what we first receive is the candidate after the ice restart.

An "ice-frag versioning" seems the safest path forward.

El vie, 5 nov 2021 a las 14:15, Juliusz Chroboczek (<[email-masked]>) escribió:

> Wish mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/wish
>

---

From: Juliusz Chroboczek <[email-masked]>
Date: Fri, 05 Nov 2021 14:38:54 +0100

> That won't solve the situation either, as the ice restart may be delayed and
> what we first receive is the candidate after the ice restart.

I've only seen this happen with Safari, and the solution I use in Galene's
native client is to have the client buffer candidates until after the
restart is sent.

> An "ice-frag versioning" seems the safest path forward.

Yes, that could probably be made to work.

-- Juliusz

---

From: Christer Holmberg <[email-masked]>
Date: Fri, 5 Nov 2021 13:42:40 +0000

Hi,

...

>   candidates for the most recent ufrag.  This is fragile and error-prone.

Isn't this what an ICE agent is assumed to do in general? Why would it send "pre-restart" candidates?

Regards,

Christer

---

From: Sergio Garcia Murillo <[email-masked]>
Date: Fri, 5 Nov 2021 15:29:20 +0100

> send "pre-restart" candidates?
The issue is that the HTTP posts are not guaranteed to keep the order in
which they are sent, so it could happen that the server receives them out
of order, and the restart is received before the pre-restart candidates.
Would be quite rare, but could happen.

Best regards
Sergio

---

From: Juliusz Chroboczek <[email-masked]>
Date: Fri, 05 Nov 2021 16:32:22 +0100

> The issue is that the HTTP posts are not guaranteed to keep the order in which
> they are sent,

I'm confused.  I was assuming you were concerned about the asynchrony
between the ICE gatherer and the ICE restart.

If the issue is sequencing the HTTP requests, then we can simply require
that there is at most one request in flight, i.e. that a request is only
sent after the previous reply has been received.  That will be enough to
ensure that HTTP requests are properly sequenced.

-- Juliusz

---

From: Sergio Garcia Murillo <[email-masked]>
Date: Fri, 5 Nov 2021 16:48:00 +0100

If you are doing an ice restart because of a network disconnection/switch,
any pending http post may be stalled, and you would have to wait for the
timeout.

So doing synchronous requests is not optimal, apart of potentially making
development on the client side harder.

El vie, 5 nov 2021 a las 16:32, Juliusz Chroboczek (<[email-masked]>) escribió:

> >     Isn't this what an ICE agent is assumed to do in general? Why would
> it send
> >     "pre-restart" candidates?
> >
> which