RFC 8838

Trickle ICE: Incremental Provisioning of Candidates for the Interactive Connectivity Establishment (ICE) Protocol

๐Ÿ“… published January 2021, from ietf

RFC 8838: Trickle ICE: Incremental Provisioning of Candidates for the Interactive Connectivity Establishment (ICE) Protocol ๐ŸŽ€

Okay bestie, this one is from the IETF (the Internet Engineering Task Force), and it's on the Standards Track ๐Ÿ’… It's dated January 2021, and its ISSN is 2070-1721.

The authors are E. Ivov (8x8 / Jitsi), J. Uberti (Google), and P. Saint-Andre (Mozilla). Their whole squad made this, so it's giving collab energy โœจ

The header doesn't list anything this RFC obsoletes or updates, so there's no drama with older docs here ๐Ÿ™ˆ

Abstract

This document describes "Trickle ICE", an extension to the Interactive Connectivity Establishment (ICE) protocol ๐Ÿฆ‹ It lets ICE agents start connectivity checks while they're still gathering candidates, by swapping candidates bit by bit over time instead of dumping them all at once. Main-character move. This method can considerably speed up setting up a communication session ๐Ÿš€

Status of This Memo

This is an Internet Standards Track document ๐ŸŒธ

It's a product of the Internet Engineering Task Force (IETF), so it represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more on Internet Standards, check Section 2 of RFC 7841 ๐Ÿ“š

For the current status, any errata, and how to give feedback, go to https://www.rfc-editor.org/info/rfc8838 ๐Ÿ’œ

Copyright (c) 2021 IETF Trust and the persons identified as the document authors. All rights reserved. ๐Ÿ”’

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as in effect on the date of publication. Please read these carefully, because they spell out your rights and restrictions for this document ๐Ÿงพ Any Code Components pulled out of this document must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions. They're provided without warranty, as described in the Simplified BSD License ๐Ÿซถ

Table of Contents

   1.  Introduction
   2.  Terminology
   3.  Determining Support for Trickle ICE
   4.  Generating the Initial ICE Description
   5.  Handling the Initial ICE Description and Generating the Initial
           ICE Response
   6.  Handling the Initial ICE Response
   7.  Forming Checklists
   8.  Performing Connectivity Checks
   9.  Gathering and Conveying Newly Gathered Local Candidates
   10. Pairing Newly Gathered Local Candidates
   11. Receiving Trickled Candidates
   12. Inserting Trickled Candidate Pairs into a Checklist
   13. Generating an End-of-Candidates Indication
   14. Receiving an End-of-Candidates Indication
   15. Subsequent Exchanges and ICE Restarts
   16. Half Trickle
   17. Preserving Candidate Order While Trickling
   18. Requirements for Using Protocols
   19. IANA Considerations
   20. Security Considerations
   21. References
     21.1.  Normative References
     21.2.  Informative References
   Appendix A.  Interaction with Regular ICE
   Appendix B.  Interaction with ICE-Lite
   Acknowledgements
   Authors' Addresses

1. Introduction โœจ

The Interactive Connectivity Establishment (ICE) protocol [RFC8445] explains how an ICE agent gathers candidates, swaps candidates with a peer ICE agent, and creates candidate pairs. Once the pairs are gathered, the ICE agent runs connectivity checks and eventually nominates and selects the pairs that will send and receive data during the session ๐Ÿ’–

Following the procedures in [RFC8445] can make session setup take kinda long ๐Ÿฅฒ That's because candidate gathering often means querying Session Traversal Utilities for NAT (STUN) servers [RFC5389] and allocating relayed candidates on Traversal Using Relay NAT (TURN) servers [RFC5766]. Lots of ICE steps can run in parallel, but the pacing requirements from [RFC8445] still need to be followed โณ

This document defines "Trickle ICE", a supplementary mode of ICE operation. Candidates can be exchanged incrementally as soon as they're available (and at the same time as other candidates are being gathered). Connectivity checks can start as soon as candidate pairs have been created ๐Ÿฆ‹ Since Trickle ICE lets candidate gathering and connectivity checks happen in parallel, it can considerably speed up setting up a communication session. It's so efficient ๐Ÿ˜ญ

This document also covers how to discover support for Trickle ICE, how the procedures in [RFC8445] are modified or supplemented when you use Trickle ICE, and how a Trickle ICE agent can interoperate with an ICE agent that complies with [RFC8445] ๐Ÿงš

Here's the tea: this document doesn't define any protocol-specific usage of Trickle ICE. Those details live in separate usage documents. Examples are [RFC8840], which defines usage with the Session Initiation Protocol (SIP) [RFC3261] and the Session Description Protocol (SDP) [RFC4566], and [XEP-0176], which defines usage with the Extensible Messaging and Presence Protocol (XMPP) [RFC6120]. Some examples in this document do use SDP and the Offer/Answer model [RFC3264] to explain the core ideas, though ๐ŸŽ€

Here's a diagram of a successful Trickle ICE exchange with a using protocol that follows the Offer/Answer model ๐Ÿ‘€

           Alice                                            Bob
             |                     Offer                     |
             |---------------------------------------------->|
             |            Additional Candidates              |
             |---------------------------------------------->|
             |                     Answer                    |
             |<----------------------------------------------|
             |            Additional Candidates              |
             |<----------------------------------------------|
             | Additional Candidates and Connectivity Checks |
             |<--------------------------------------------->|
             |<========== CONNECTION ESTABLISHED ===========>|

                               Figure 1: Flow

The main body of this document describes what Trickle ICE agents do, roughly in the order things happen during an ICE session ๐Ÿ“‹

  1. Determining support for Trickle ICE
  2. Generating the initial ICE description
  3. Handling the initial ICE description and generating the initial ICE response
  4. Handling the initial ICE response
  5. Forming checklists, pruning candidates, performing connectivity checks, etc.
  6. Gathering and conveying candidates after the initial ICE description and response
  7. Handling inbound trickled candidates
  8. Generating and handling the end-of-candidates indication
  9. Handling ICE restarts

Fun fact: there's quite a bit of real operational experience behind the technique, going back to 2005, when the XMPP Jingle extension defined a "dribble mode" as specified in [XEP-0176] ๐Ÿ•ฐ๏ธ This document also picks up feedback from folks who've implemented and deployed the technique over the years ๐Ÿซถ

2. Terminology ๐Ÿ“–

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. Only the capitalized versions count, so read them carefully ๐Ÿ™ƒ

This specification uses all the terminology defined for Interactive Connectivity Establishment in [RFC8445]. On top of that, it defines these terms:

Empty Checklist: A checklist that doesn't contain any candidate pairs at the start, because they'll be added one by one as they're trickled. (This doesn't happen with a regular ICE agent, since all candidate pairs are already known when the agent creates the checklist set.) ๐Ÿซ™

Full Trickle: The typical way Trickle ICE agents operate. The initial ICE description can include any number of candidates (even zero), and it doesn't need to include a full generation of candidates the way half trickle does ๐Ÿ’ซ

Generation: All of the candidates conveyed within an ICE session, correlated with one particular combination of Username Fragment and Password ๐Ÿงฉ

Half Trickle: A Trickle ICE mode where the initiator gathers a full generation of candidates strictly before creating and conveying the initial ICE description. Once that's sent, regular ICE agents, which don't need Trickle ICE support, can process it. It also lets Trickle-ICE-capable responders keep gathering candidates and running connectivity checks without blocking, so you get roughly "half" the perks of Trickle ICE ๐ŸŒ— The half-trickle mechanism is mostly meant for when the responder's support for Trickle ICE can't be confirmed before the initial ICE description is conveyed.

ICE Description: Any attributes related to the ICE session (other than candidates) that are needed to configure an ICE agent. These include but aren't limited to the Username Fragment, the Password, and other attributes ๐Ÿ› ๏ธ

Trickled Candidates: Candidates that a Trickle ICE agent conveys after it has conveyed or responded to the initial ICE description, but still within the same ICE session. Trickled candidates can be conveyed in parallel with candidate gathering and connectivity checks โšก

Trickling: The act of incrementally conveying trickled candidates ๐ŸŒŠ

3. Determining Support for Trickle ICE โœจ

okay so bestie, to fully support Trickle ICE, using protocols SHOULD bring in one of these mechanisms so implementations can figure out whether Trickle ICE is supported ๐Ÿ”:

  1. Provide a capabilities discovery method so agents can verify Trickle ICE support before starting a session (XMPP's Service Discovery [XEP-0030] is one such mechanism ๐Ÿ’…).
  2. Make support for Trickle ICE mandatory so user agents can just assume it's there ๐Ÿซถ.

If a using protocol doesn't have a way to figure out ahead of time whether Trickle ICE is supported, agents can use the half-trickle procedure described in Section 16 ๐Ÿ™ˆ.

Before sending the initial ICE description, agents whose using protocols support capabilities discovery can check whether the remote party supports Trickle ICE. If an agent finds out the remote party doesn't support it, it MUST fall back to using regular ICE or abandon the entire session ๐Ÿ’€.

Even if a using protocol has no capabilities discovery method, a user agent can show that it supports Trickle ICE inside the ICE description by including an ICE option of 'trickle'. This token MUST be provided either at the session level or, if at the data stream level, for every data stream (an agent MUST NOT specify Trickle ICE support for some data streams but not others). ๐Ÿ“ Note: The encoding of the 'trickle' ICE option, and the message(s) used to carry it to the peer, are protocol specific. For instance, the encoding for SDP [RFC4566] is defined in [RFC8840].

Dedicated discovery semantics and half trickle are needed only before an ICE session starts. Once an ICE session is established and both parties have confirmed Trickle ICE support, either agent can use full trickle for later exchanges (see also Section 15) ๐Ÿฆ‹.


4. Generating the Initial ICE Description ๐ŸŽ€

An ICE agent can start gathering candidates as soon as it gets a hint that communication is coming (like a user-interface cue or an explicit request to start a session) ๐Ÿ‘€. Unlike regular ICE, Trickle ICE implementations don't have to gather candidates in a blocking way. So unless half trickle is being used, the user experience gets better when the initiating agent generates and sends its initial ICE description as early as possible, which lets the remote party start gathering and trickling candidates sooner ๐Ÿš€.

An initiator MAY include any mix of candidates when it conveys the initial ICE description. That could mean sending every candidate it plans to use (like half trickle does), sending only a publicly reachable IP address (for example, a candidate at a data relay that's known to not be behind a firewall), or sending no candidates at all. With no candidates, the initiator can get the responder's initial candidate list sooner, and the responder can start gathering more quickly โšก.

For candidates included in the initial ICE description, calculating priorities and foundations, figuring out redundancy, and everything else works just like regular ICE [RFC8445] ๐Ÿ’œ.


5. Handling the Initial ICE Description and Generating the Initial ICE Response ๐ŸŒˆ

When a responder gets the initial ICE description, it first checks whether the ICE description or the initiator indicates Trickle ICE support, as explained in Section 3 ๐Ÿ”Ž. If it doesn't, the responder MUST process the initial ICE description according to regular ICE procedures [RFC8445]. (Or, if no ICE support is detected at all, it follows the relevant processing rules for the using protocol, such as the Offer/Answer processing rules [RFC3264].) But if Trickle ICE support is confirmed, the responder automatically assumes regular ICE support too ๐Ÿซถ.

If the initial ICE description shows Trickle ICE support, the responder works out its role and starts gathering and prioritizing candidates. While it's doing that, it also sends back an initial ICE response, so both the initiator and the responder can form checklists and start connectivity checks ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ.

A responder can respond to the initial ICE description at any point while it's still gathering candidates. The initial ICE response MAY contain any set of candidates, including all of them or none at all. (Sending no candidates is useful because the initial ICE response goes out as fast as possible, so both parties can see the ICE session as actively being negotiated right away ๐Ÿ“.)

As noted in Section 3, in using protocols that use SDP, the initial ICE response can show Trickle ICE support by including a token of trickle in the ice-options attribute ๐Ÿงš.


6. Handling the Initial ICE Response ๐Ÿ’Œ

When the initiator processes the initial ICE response, it follows regular ICE procedures to determine its role. After that, it forms checklists (Section 7) and performs connectivity checks (Section 8) โœ….


7. Forming Checklists ๐Ÿ“‹

According to regular ICE procedures [RFC8445], for candidate pairing to be possible and for redundant candidates to get pruned, the candidates need to be provided in the initial ICE description and the initial ICE response. Trickle ICE is different: checklists can be empty until candidates are conveyed or received ๐Ÿคฏ. So a Trickle ICE agent handles checklist formation and candidate pairing a little differently from a regular ICE agent. It still forms the checklists, but it only fills a given checklist once it actually has candidate pairs for that checklist. Every checklist starts out in the Running state, even if it's empty (this is consistent with Section 6.1.2.1 of [RFC8445]) ๐ŸŒธ.


8. Performing Connectivity Checks โšก

As specified in [RFC8445], whenever timer Ta fires, only checklists in the Running state get picked when scheduling connectivity checks for candidate pairs. So a Trickle ICE agent MUST keep each checklist in the Running state for as long as it expects candidate pairs to keep getting added to it ๐Ÿ™Œ. After that, the checklist state is set according to the procedures in [RFC8445].

Whenever timer Ta fires and an empty checklist gets picked, nothing happens for that list. Without waiting for timer Ta to expire again, the agent selects the next checklist in the Running state, in accordance with Section 6.1.4.2 of [RFC8445] ๐Ÿ”.

Section 7.2.5.4 of [RFC8445] requires that agents update checklists and timer states when a connectivity check transaction completes. During that update, regular ICE agents set a checklist to Failed if both of these conditions are satisfied:

  • all of the pairs in the checklist are in either the Failed state or the Succeeded state; and
  • there is not a pair in the valid list for each component of the data stream.

With Trickle ICE, that situation happens a lot while candidate gathering and trickling are still going on, even though future checks might totally succeed ๐Ÿ˜ญ. So Trickle ICE agents add these conditions to the list above:

  • all candidate gathering has completed, and the agent is not expecting to discover any new local candidates; and
  • the remote agent has conveyed an end-of-candidates indication for that checklist as described in Section 13.

9. Gathering and Conveying Newly Gathered Local Candidates ๐Ÿฆ‹

After Trickle ICE agents have sent their initial ICE descriptions and initial ICE responses, they'll most likely keep gathering new local candidates as STUN, TURN, and other non-host candidate gathering mechanisms start to pay off ๐ŸŒŸ. Whenever an agent finds a new candidate, it computes the candidate's priority, type, foundation, and component ID according to regular ICE procedures.

Then the new candidate gets checked for redundancy against the existing list of local candidates. If its transport address and base match an existing candidate's, it's considered redundant and gets ignored ๐Ÿ—‘๏ธ. This often happens with server-reflexive candidates that match the host addresses they were obtained from (for example, when those host addresses are public IPv4 addresses). Unlike regular ICE, Trickle ICE agents consider the new candidate redundant regardless of its priority.

Next, the agent "trickles" the newly discovered candidate(s) to the remote agent. Delivery is handled by a using protocol such as SIP or XMPP, and Trickle ICE puts no restrictions on how that's done. (For example, some using protocols might choose not to trickle updates for server-reflexive candidates and instead rely on discovering peer-reflexive ones ๐Ÿ’….)

When candidates are trickled, the using protocol MUST deliver each candidate (and any end-of-candidates indication as described in Section 13) to the receiving Trickle ICE implementation exactly once and in the same order it was conveyed ๐ŸŽฏ. If the using protocol does any candidate retransmissions, the ICE implementation shouldn't see them ๐Ÿ™ˆ.

Candidate trickling also needs to be tied to a specific ICE session. That way, if there's an ICE restart, any delayed updates from a previous session can be recognized and ignored by the receiving party ๐Ÿšซ. For example, using protocols that signal candidates via SDP might include a Username Fragment value in the corresponding a=candidate line, like this:

a=candidate:1 1 UDP 2130706431 2001:db8::1 5000 typ host ufrag 8hhY

Or, as another example, WebRTC implementations might include a Username Fragment in the JavaScript objects that represent candidates ๐Ÿงšโ€โ™€๏ธ.

๐Ÿ“ Note: The using protocol needs to give both parties a way to indicate and agree on the ICE session in force (as identified by the Username Fragment and Password combination), so they have a consistent view of which candidates are supposed to be paired. This is especially important for ICE restarts (see Section 15) ๐Ÿ‘‘.

๐Ÿ“ Note: A using protocol might prefer not to trickle server-reflexive candidates to entities that are known to be publicly accessible, since sending a direct STUN binding request is likely to reach the destination faster than a trickle update traveling through the signaling path ๐Ÿš€๐Ÿ’–.

10. Pairing Newly Gathered Local Candidates โœจ

okay so bestie, this is where the agent takes the local candidates it just gathered and starts building candidate pairs ๐Ÿ”—๐Ÿ’– the ICE spec [RFC8445] already explains how pairing works, but Trickle ICE has a few extra rules on top, so let's go through them ๐Ÿซถ

  • A Trickle ICE agent MUST NOT pair a local candidate until it has been trickled to the remote party. no cap, this is a hard rule ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’…
  • Once the agent has conveyed the local candidate to the remote party, it checks whether any remote candidates are already known for this same stream and component. if none are known, the agent just adds the new candidate to its list of local candidates and doesn't pair it yet ๐ŸŒธ
  • otherwise, if the agent has already learned one or more remote candidates for this stream and component, it tries to pair the new local candidate as described in [RFC8445] ๐Ÿฆ‹
  • if a newly formed pair has a local candidate whose type is server-reflexive, the agent MUST replace that local candidate with its base before completing the relevant redundancy tests ๐Ÿงš
  • the agent prunes redundant pairs by following the rules in Section 6.1.2.4 of [RFC8445], but it only checks existing pairs whose state is Waiting or Frozen ๐Ÿ’œ this is so it doesn't remove pairs with connectivity checks in flight (In-Progress) or pairs that already have a definitive result (Succeeded or Failed) ๐Ÿ˜ญ
  • if, after the redundancy tests, the checklist already has the maximum number of candidate pairs (100 by default as per [RFC8445]), the agent SHOULD discard any pairs in the Failed state to make room ๐Ÿ“ if there are no Failed pairs, the agent SHOULD discard a pair with a lower priority than the new pair, until the number of pairs equals the maximum. this matches Section 6.1.2.5 of [RFC8445] ๐Ÿ‘‘

11. Receiving Trickled Candidates ๐ŸŽ€

at any time during an ICE session, a Trickle ICE agent might get new candidates from the remote agent ๐Ÿ“ฌ it'll try to form a candidate pair from them, and again the ICE spec [RFC8445] is the base, with these provisos:

  • the agent checks whether any local candidates are already known for this same stream and component. if not, it just adds the new candidate to its list of remote candidates without pairing it ๐ŸŒˆ
  • otherwise, if the agent has already gathered one or more local candidates for this stream and component, it tries to pair the new remote candidate as described in [RFC8445] ๐Ÿฆ‹
  • if a newly formed pair has a local candidate whose type is server-reflexive, the agent MUST replace that local candidate with its base before doing the redundancy check in the next step ๐Ÿงš
  • the agent prunes redundant pairs as described below, but only checks existing pairs whose state is Waiting or Frozen ๐Ÿ’œ same reasoning as before: pairs with checks In-Progress or a definitive result of Succeeded or Failed stay put ๐Ÿ™ˆ
    • A. if the agent finds a redundancy between two pairs and one of them contains a newly received remote candidate whose type is peer-reflexive, the agent SHOULD discard the pair containing that candidate, set the priority of the existing pair to the priority of the discarded pair, and re-sort the checklist โœจ this helps fix problems with remote peer-reflexive candidates that get a STUN Binding request before the candidate is trickled to the receiving agent ๐Ÿซ  (like when the two agents see pair priorities differently, since one might call the same candidate peer-reflexive while the other calls it server-reflexive)
    • B. the agent then applies the rules in Section 6.1.2.4 of [RFC8445] ๐Ÿ’…
  • if, after the redundancy tests, the checklist already has the maximum number of candidate pairs (100 by default as per [RFC8445]), the agent SHOULD discard any Failed pairs to make room ๐Ÿ“ if there are none, it SHOULD discard a lower-priority pair than the new one until the count equals the maximum. this is consistent with Section 6.1.2.5 of [RFC8445] ๐Ÿ‘‘

12. Inserting Trickled Candidate Pairs into a Checklist โœจ

Okay so, bestie, this is where a newly formed candidate pair finds its home ๐Ÿก. After a local agent has trickled a candidate and formed a candidate pair from that local candidate (Section 9), or after a remote agent has received a trickled candidate and formed a candidate pair from that remote candidate (Section 11), a Trickle ICE agent adds the new candidate pair to a checklist as this section defines. ๐Ÿ’–

To make this easier to picture, the spec gives us a table of all the checklists in an agent ๐Ÿ“Š. Heads up: at first, foundation f5 has no candidate pairs at all ๐Ÿฅบ.

            +=================+====+====+====+====+====+
            |                 | f1 | f2 | f3 | f4 | f5 |
            +=================+====+====+====+====+====+
            | s1 (Audio.RTP)  | F  | F  | F  |    |    |
            +-----------------+----+----+----+----+----+
            | s2 (Audio.RTCP) | F  | F  | F  | F  |    |
            +-----------------+----+----+----+----+----+
            | s3 (Video.RTP)  | F  |    |    |    |    |
            +-----------------+----+----+----+----+----+
            | s4 (Video.RTCP) | F  |    |    |    |    |
            +-----------------+----+----+----+----+----+

                Table 1: Example of Checklist State

Each row is a component for a given data stream. So s1 and s2 could be the RTP and RTP Control Protocol (RTCP) components for audio, and each row is basically its own checklist in the checklist set ๐ŸŽ€. Each column is one foundation, and each cell is one candidate pair. In this section's tables, "F" means "frozen", "W" means "waiting", and "S" means "succeeded", and "^^" marks the candidate pairs that were just added ๐Ÿฆ‹.

When an agent starts ICE processing, following Section 6.1.2.6 of [RFC8445], it unfreezes, for each foundation, the pair with the lowest component ID. If the component IDs are equal, it goes with the highest priority instead. That's the topmost pair in every column ๐Ÿ‘‘. Here's the starting vibe:

            +=================+====+====+====+====+====+
            |                 | f1 | f2 | f3 | f4 | f5 |
            +=================+====+====+====+====+====+
            | s1 (Audio.RTP)  | W  | W  | W  |    |    |
            +-----------------+----+----+----+----+----+
            | s2 (Audio.RTCP) | F  | F  | F  | W  |    |
            +-----------------+----+----+----+----+----+
            | s3 (Video.RTP)  | F  |    |    |    |    |
            +-----------------+----+----+----+----+----+
            | s4 (Video.RTCP) | F  |    |    |    |    |
            +-----------------+----+----+----+----+----+

                  Table 2: Initial Checklist State

Then, as the checks go on (see Section 7.2.5.4 of [RFC8445]), every pair that hits the Succeeded state ("S") makes the agent unfreeze all pairs for all data streams that share its foundation ๐Ÿ”“. So if the pair in column 1, row 1 succeeds, the agent unfreezes the pairs in column 1, rows 2, 3, and 4. Iconic. ๐ŸŒˆ

            +=================+====+====+====+====+====+
            |                 | f1 | f2 | f3 | f4 | f5 |
            +=================+====+====+====+====+====+
            | s1 (Audio.RTP)  | S  | W  | W  |    |    |
            +-----------------+----+----+----+----+----+
            | s2 (Audio.RTCP) | W  | F  | F  | W  |    |
            +-----------------+----+----+----+----+----+
            | s3 (Video.RTP)  | W  |    |    |    |    |
            +-----------------+----+----+----+----+----+
            | s4 (Video.RTCP) | W  |    |    |    |    |
            +-----------------+----+----+----+----+----+

              Table 3: Checklist State with Succeeded
                           Candidate Pair

Trickle ICE keeps all of these rules for "static" checklist sets too ๐Ÿงš. So if a Trickle ICE agent started its checks with every pair already present, the way the pair states change would look exactly like a regular ICE agent. No difference at all, ngl ๐Ÿ’….

The big difference with Trickle ICE is that checklist sets can keep changing, since candidates can show up after checks have already started ๐Ÿ˜ญ. When that happens, the agent sets the state of the new pair using the rules below. โœจ

Rule 1: If the newly formed pair has the lowest component ID and, if the component IDs are equal, the highest priority of any candidate pair for this foundation (so basically, if it's the topmost pair in its column), set the state to Waiting. For example, this happens if the newly formed pair lands in column 5, row 1. This rule matches Section 6.1.2.6 of [RFC8445]. ๐Ÿฅ‡

            +=================+====+====+====+====+=====+
            |                 | f1 | f2 | f3 | f4 | f5  |
            +=================+====+====+====+====+=====+
            | s1 (Audio.RTP)  | S  | W  | W  |    | ^W^ |
            +-----------------+----+----+----+----+-----+
            | s2 (Audio.RTCP) | W  | F  | F  | W  |     |
            +-----------------+----+----+----+----+-----+
            | s3 (Video.RTP)  | W  |    |    |    |     |
            +-----------------+----+----+----+----+-----+
            | s4 (Video.RTCP) | W  |    |    |    |     |
            +-----------------+----+----+----+----+-----+

                 Table 4: Checklist State with Newly
                         Formed Pair, Rule 1

Rule 2: If there's at least one pair in the Succeeded state for this foundation, set the state to Waiting. For example, this happens if the pair in column 5, row 1 succeeded and the newly formed pair lands in column 5, row 2. This rule matches Section 7.2.5.3.3 of [RFC8445]. ๐Ÿซถ

            +=================+====+====+====+====+=====+
            |                 | f1 | f2 | f3 | f4 | f5  |
            +=================+====+====+====+====+=====+
            | s1 (Audio.RTP)  | S  | W  | W  |    | S   |
            +-----------------+----+----+----+----+-----+
            | s2 (Audio.RTCP) | W  | F  | F  | W  | ^W^ |
            +-----------------+----+----+----+----+-----+
            | s3 (Video.RTP)  | W  |    |    |    |     |
            +-----------------+----+----+----+----+-----+
            | s4 (Video.RTCP) | W  |    |    |    |     |
            +-----------------+----+----+----+----+-----+

                 Table 5: Checklist State with Newly
                         Formed Pair, Rule 2

Rule 3: In every other case, set the state to Frozen. For example, this happens if the newly formed pair lands in column 3, row 3. ๐ŸงŠ

            +=================+====+====+=====+====+====+
            |                 | f1 | f2 | f3  | f4 | f5 |
            +=================+====+====+=====+====+====+
            | s1 (Audio.RTP)  | S  | W  | W   |    | S  |
            +-----------------+----+----+-----+----+----+
            | s2 (Audio.RTCP) | W  | F  | F   | W  | W  |
            +-----------------+----+----+-----+----+----+
            | s3 (Video.RTP)  | W  |    | ^F^ |    |    |
            +-----------------+----+----+-----+----+----+
            | s4 (Video.RTCP) | W  |    |     |    |    |
            +-----------------+----+----+-----+----+----+

                 Table 6: Checklist State with Newly
                         Formed Pair, Rule 3

13. Generating an End-of-Candidates Indication ๐Ÿ

Once candidate gathering finishes or times out for an ICE session tied to a specific data stream, the agent generates an "end-of-candidates" indication for that session and sends it to the remote agent over the signaling channel ๐Ÿ“จ. The exact form depends on the using protocol, but the indication MUST specify the generation (the Username Fragment and Password combination) ๐Ÿ”‘. That's how an agent matches the end-of-candidates indication to the right ICE session. Here's how it can be sent:

  • As part of an initiation request. This is usually how it goes with the initial ICE description for half trickle ๐ŸŒธ
  • Along with the last candidate an agent sends for a stream ๐ŸŽ
  • As a standalone notification. For example, after STUN Binding requests or TURN Allocate requests to a server time out and the agent is no longer actively gathering candidates ๐Ÿ˜ด

Sending the end-of-candidates indication on time really matters ๐Ÿ•ฐ๏ธ. It avoids confusion and speeds up the end of ICE processing. Specifically:

  • A controlled Trickle ICE agent SHOULD convey an end-of-candidates indication after it has finished gathering for a data stream, unless ICE processing ends before the agent gets the chance to finish gathering. ๐Ÿฆ‹
  • A controlling agent MAY conclude ICE processing before it has conveyed end-of-candidates indications for all streams. However, it is RECOMMENDED for a controlling agent to convey end-of-candidates indications whenever possible. That keeps things consistent and keeps middleboxes and controlled agents up to date on how ICE processing is going ๐Ÿ‘‘

When an agent conveys an end-of-candidates indication while trickling (instead of in the initial ICE description or a response to it), the using protocol is responsible for defining how the indication gets tied to one or more specific data streams ๐Ÿงฉ.

An agent MAY also choose to generate an end-of-candidates indication before candidate gathering has actually finished, if it decides gathering has been going on for longer than an acceptable amount of time โณ. Just remember, an agent MUST NOT convey any more candidates after it has conveyed an end-of-candidates indication. No take-backsies ๐Ÿ™…โ€โ™€๏ธ.

When an agent performs half trickle, it SHOULD convey an end-of-candidates indication together with its initial ICE description, unless it's planning to possibly trickle more candidates (for example, in case the remote party turns out to support Trickle ICE) ๐Ÿคž.

After an agent conveys the end-of-candidates indication, it updates the state of the matching checklist as Section 8 explains ๐Ÿ“‹. From that point on, an agent MUST NOT trickle any new candidates within this ICE session. So if you want to add new candidates to the negotiation, the only way is an ICE restart (see Section 15) ๐Ÿ”„.

This spec doesn't override the regular ICE rules for ending ICE processing ๐Ÿ™Œ. So even when end-of-candidates indications have been conveyed, an agent still has to go through pair nomination. Also, if pairs have been nominated for components and data streams, ICE processing MAY still conclude even if end-of-candidates indications haven't come in for every stream. Either way, an agent MUST NOT trickle any new candidates within an ICE session after nomination of a candidate pair, as Section 8.1.1 of [RFC8445] describes ๐Ÿ’€โœจ.

14. Receiving an End-of-Candidates Indication ๐Ÿ’Œ

okay bestie, so getting an end-of-candidates indication lets an agent update its checklist states ๐Ÿ“‹. If valid pairs don't exist for every component in every data stream, the agent can figure out that ICE processing has failed ๐Ÿ˜ญ. It also helps things move faster when a candidate pair has already been validated but uses a lower-preference transport like TURN โšก. In that situation, an implementation MAY wait and see if higher-priority candidates show up ๐Ÿ‘€. The end-of-candidates indication basically says "don't wait, nothing better is coming" ๐Ÿซถ.

When an agent gets an end-of-candidates indication for a specific data stream, it updates the state of the relevant checklist as per Section 8 ๐Ÿ’…. This can mean some checklists get marked as Failed ๐Ÿ’€. If the checklist is still in the Running state after the update, the agent notes that it got an end-of-candidates indication and takes that into account in future checklist updates ๐Ÿง .

After an agent has received an end-of-candidates indication, it MUST ignore any newly received candidates for that data stream or data session ๐Ÿšซ. No late arrivals, periodt โœจ.

15. Subsequent Exchanges and ICE Restarts ๐Ÿ”„

Before conveying an end-of-candidates indication, either agent MAY send more candidate info at any time the using protocol allows ๐Ÿ’ฌ. When that happens, the agents use the semantics from [RFC8445] (like checking the Username Fragment and Password combo) to figure out whether the new candidate info needs an ICE restart ๐Ÿ•ต๏ธโ€โ™€๏ธ.

If an ICE restart does happen, the agents can assume Trickle ICE is still supported, as long as support was figured out earlier ๐Ÿฆ‹. So they can keep doing Trickle ICE behavior, the same way they would in an initial exchange of ICE descriptions where support was determined through a capabilities discovery method ๐ŸŒˆ.

16. Half Trickle ๐ŸŒ—

Okay, half trickle is giving "compromise" energy and I'm here for it ๐Ÿฅน. The initiator sends the initial ICE description with a usable but not necessarily full generation of candidates ๐Ÿ“. This makes sure a regular ICE responder can still process the description ๐Ÿงธ. It's mostly for situations where Trickle ICE support can't be confirmed before the initial ICE description is sent ๐Ÿคทโ€โ™€๏ธ.

The initial ICE description says "hey, I support Trickle ICE!" so the responder can reply with less than a full generation of candidates and trickle the rest later ๐Ÿ’–. The initial ICE description for half trickle can include an end-of-candidates indication, but it's not mandatory ๐Ÿ™ƒ. Why? Because if trickle support is confirmed, the initiator can just trickle more candidates before sending an end-of-candidates indication โœจ.

Half trickle is useful when an agent has no way to check ahead of time whether the remote party supports Trickle ICE ๐Ÿ”. Since the initial ICE description has a full generation of candidates, a regular ICE agent can handle it no problem ๐Ÿ’ช. Meanwhile, a Trickle ICE agent can still use the optimization defined in this specification ๐ŸŽ€. Negotiation doesn't fail for the regular agent, and the Trickle ICE agent still gets roughly half the Trickle ICE benefits ๐ŸŒธ.

Half trickle is only needed during an initial exchange of ICE descriptions ๐Ÿ™Œ. Once both parties have received an ICE description from their peer, they can each reliably determine Trickle ICE support and use it for all later exchanges (see Section 15) ๐Ÿ’œ.

Sometimes half trickle can bring more than half the UX improvement ๐Ÿคฉ. This happens when an agent starts gathering candidates based on UI cues that the user is about to start an interaction, like keypad activity or the phone going off hook ๐Ÿ“ž. That means some or all of the candidate gathering could be finished before the agent actually has to send the candidate info ๐Ÿƒโ€โ™€๏ธ. Since the responder can trickle candidates, both agents can start connectivity checks and finish ICE processing earlier than with regular ICE, and potentially as early as with full trickle ๐Ÿš€.

But anticipation isn't always possible ๐Ÿ˜ฎโ€๐Ÿ’จ. For example, a multipurpose user agent, or a WebRTC web page where calling is a non-central feature (like calling a support line when the main features break), might not be able to tell call intentions apart from other user activity ๐Ÿ“ต. In those cases, full trickle is most likely to give the ideal user experience ๐Ÿ‘‘. Even so, half trickle is still an upgrade over regular ICE, because responders get a better experience too ๐Ÿซถ.

17. Preserving Candidate Order While Trickling ๐ŸŽข

Here's the tea โ˜•. A key thing about regular ICE is that connectivity checks for a specific foundation and component are attempted at the same time by both agents ๐Ÿค. This way, any firewalls or NATs in front of the agents whitelist both endpoints and let everything through except the first ("suicide") packets ๐Ÿงฑ. It also matters for unfreezing candidates at the right time โฐ. It's not crucial, but keeping this behavior in Trickle ICE will likely improve ICE performance ๐Ÿ“ˆ.

To make that happen, when trickling candidates, agents SHOULD respect the order of components as shown by their component IDs ๐Ÿ”ข. In other words, candidates for a given component SHOULD NOT be sent before candidates for a component with a lower ID number within the same foundation ๐Ÿ™…โ€โ™€๏ธ. Also, candidates SHOULD be paired, using the procedures in Section 12, in the same order they're sent ๐Ÿงฉ.

Here's an example SDP description with two components (RTP and RTCP) and two foundations (host and server-reflexive) ๐ŸŽ€:

v=0
o=jdoe 2890844526 2890842807 IN IP4 10.0.1.1
s=
c=IN IP4 10.0.1.1
t=0 0
a=ice-pwd:asd88fgpdd777uzjYhagZg
a=ice-ufrag:8hhY
m=audio 5000 RTP/AVP 0
a=rtpmap:0 PCMU/8000
a=candidate:1 1 UDP 2130706431 10.0.1.1 5000 typ host
a=candidate:1 2 UDP 2130706431 10.0.1.1 5001 typ host
a=candidate:2 1 UDP 1694498815 192.0.2.3 5000 typ srflx
    raddr 10.0.1.1 rport 8998
a=candidate:2 2 UDP 1694498815 192.0.2.3 5001 typ srflx
    raddr 10.0.1.1 rport 8998

For this candidate info, the RTCP host candidate would not be sent before the RTP host candidate ๐Ÿ™…โ€โ™€๏ธ. Similarly, the RTP server-reflexive candidate would be sent together with or before the RTCP server-reflexive candidate ๐Ÿ’….

18. Requirements for Using Protocols ๐Ÿ“œ

To fully enable Trickle ICE, this specification defines the following requirements for using protocols ๐ŸŒŸ.

  • A using protocol SHOULD provide a way for parties to advertise and discover support for Trickle ICE before an ICE session begins (see Section 3) ๐Ÿ“ฃ.
  • A using protocol MUST provide methods for incrementally conveying (i.e., "trickling") additional candidates after conveying the initial ICE description (see Section 9) ๐ŸŒŠ.
  • A using protocol MUST deliver each trickled candidate or end-of-candidates indication exactly once and in the same order it was conveyed (see Section 9) ๐ŸŽฏ.
  • A using protocol MUST provide a mechanism for both parties to indicate and agree on the ICE session in force (see Section 9) ๐Ÿค.
  • A using protocol MUST provide a way for parties to communicate the end-of-candidates indication, which MUST specify the particular ICE session to which the indication applies (see Section 13) ๐Ÿ.

19. IANA Considerations ๐Ÿ—‚๏ธ

IANA has registered the following ICE option in the "ICE Options" subregistry of the "Interactive Connectivity Establishment (ICE) registry", following the procedures defined in [RFC6336] โœจ.

ICE Option: trickle

Contact: IESG <iesg@ietf.org>

Change controller: IESG

Description: An ICE option of 'trickle' indicates support for incremental communication of ICE candidates ๐Ÿ’ฌ.

Reference: RFC 8838 ๐ŸŽ€

20. Security Considerations ๐Ÿ”

Okay, this part is serious, so listen up ๐Ÿšจ. This specification inherits most of its semantics from [RFC8445], which means all the security considerations described there apply to Trickle ICE ๐Ÿ›ก๏ธ. No skipping them, bestie ๐Ÿ˜ค.

If the privacy implications of revealing host addresses on an endpoint device are a concern (see, for example, the discussion in [RFC8828] and in Section 19 of [RFC8445]), agents can generate ICE descriptions that contain no candidates ๐Ÿ™ˆ. Then they only trickle candidates that don't reveal host addresses (e.g., relayed candidates) ๐Ÿ•ถ๏ธ. Privacy protected, iconic behavior ๐Ÿ‘‘.

21. References ๐Ÿ“š

21.1. Normative References ๐Ÿ’œ

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8445] Keranen, A., Holmberg, C., and J. Rosenberg, "Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal", RFC 8445, DOI 10.17487/RFC8445, July 2018, <https://www.rfc-editor.org/info/rfc8445>.

21.2. Informative References โœจ

Okay bestie, here's the "if you want the backstory" reading list ๐Ÿ“š๐Ÿซถ Every one of these is cited somewhere earlier, and the authors put them here so you can go deeper.


Appendix A. Interaction with Regular ICE ๐ŸŒท

Okay so ICE was designed to be super flexible and adapt to as many network setups as possible ๐Ÿงš But even with all that flexibility, ICE as specified in [RFC8445] does not support Trickle ICE by itself. This appendix is about how trickling candidates interacts with regular ICE, and honestly it's a whole plot twist ๐Ÿ˜ญ

[RFC8445] describes the conditions you need to update checklists and timer states while an ICE agent is in the Running state. Those conditions get checked when a transaction completes, and one of them says:

   |  if there is not a valid pair in the valid list for each component
   |  of the data stream associated with the checklist, the state of the
   |  checklist is set to Failed.

This can be a real problem and cause ICE processing to fail too early in a bunch of situations. Here's one case that's giving drama ๐Ÿ’€

  1. Alice and Bob are both in different networks behind Network Address Translation (NAT). Alice and Bob have different addresses themselves, but both networks use the same private internet block (for example, the "20-bit block" 172.16/12 specified in [RFC1918]).
  2. Alice sends Bob the candidate 172.16.0.1, which just so happens to be an existing host on Bob's network. Oops ๐Ÿ™ˆ
  3. Bob makes a candidate pair from his host candidate and 172.16.0.1, puts that one pair into a checklist, and starts checks.
  4. Those checks reach the host at 172.16.0.1 on Bob's network, which replies with an ICMP "port unreachable" error. Per [RFC8445], Bob marks the transaction as Failed. Rude ๐Ÿ’…

At this point, the checklist only has a Failed pair, and the valid list is empty. That makes the data stream fail and maybe all of ICE processing too, even though Trickle ICE agents can send over candidates later that would actually work. So close, yet so cursed ๐Ÿ˜ญ

There's a similar race condition if the initial ICE description from Alice only has candidates that Bob can tell are unreachable from any of his gathered candidates. For example, this happens if Bob's candidates are all IPv4 addresses and the very first candidate he gets from Alice is an IPv6 one. Mismatch era ๐Ÿฅ€

Another potential problem shows up when a non-Trickle ICE implementation starts an interaction with a Trickle ICE implementation. Here's that one:

  1. Alice's client has a non-Trickle ICE implementation.
  2. Bob's client supports Trickle ICE.
  3. Alice and Bob are behind NATs with address-dependent filtering [RFC4787].
  4. Bob has two STUN servers, but one of them is unreachable right now.

Once Bob's agent gets Alice's initial ICE description, it would immediately start connectivity checks. It would also start gathering candidates, and that would take forever because of the unreachable STUN server. By the time Bob's answer is ready and sent to Alice, Bob's connectivity checks might have already failed. Alice can't start her connectivity checks and punch holes in her NAT until she gets Bob's answer, so her NAT would be filtering Bob's checks as coming from an unknown endpoint. Not the vibe ๐Ÿšซ


Appendix B. Interaction with ICE-Lite ๐Ÿฆ‹

The behavior of ICE-lite agents that can do Trickle ICE doesn't require any special rules beyond the ones already defined in this specification and [RFC8445]. So this section is just here for information, no pressure โœจ

An ICE-lite agent would generate candidate information as per [RFC8445] and would say it supports Trickle ICE. Since that candidate information includes a full generation of candidates, it would also come with an end-of-candidates indication ๐Ÿ

When doing full trickle, a full ICE implementation could send the initial ICE description, or the response to one, with no candidates at all. After it gets a response that identifies the remote agent as an ICE-lite implementation, the initiator can choose not to trickle any more candidates. The same goes when the ICE-lite agent starts the interaction and the full ICE agent is the responder. In these cases, the connectivity checks are enough for the ICE-lite implementation to discover all the potentially useful candidates as peer-reflexive candidates. Main character energy, no extra signaling needed ๐Ÿ‘‘ Here's an example of one ICE session using SDP syntax:

        ICE-Lite                                          Bob
         Agent
           |   Offer (a=ice-lite a=ice-options:trickle)    |
           |---------------------------------------------->|
           |                                               |no cand
           |         Answer (a=ice-options:trickle)        |trickling
           |<----------------------------------------------|
           |              Connectivity Checks              |
           |<--------------------------------------------->|
  peer rflx|                                               |
 cand disco|                                               |
           |<========== CONNECTION ESTABLISHED ===========>|

                          Figure 2: Example

Not only does this approach cut down on signaling traffic, it also removes the need to discover STUN Bindings or make TURN allocations. That can seriously lighten ICE processing, and I'm obsessed ๐Ÿซถ๐Ÿ’–


Acknowledgements ๐Ÿ’œ

The authors would like to thank Bernard Aboba, Flemming Andreasen, Rajmohan Banavi, Taylor Brandstetter, Philipp Hancke, Christer Holmberg, Ari Kerรคnen, Paul Kyzivat, Jonathan Lennox, Enrico Marocco, Pal Martinsen, Nils Ohlmeier, Thomas Stach, Peter Thatcher, Martin Thomson, Brandon Williams, and Dale Worley for their reviews and suggestions that made this document better. Sarah Banks, Roni Even, and David Mandelberg completed the OPSDIR, GenART, and security reviews, respectively. Thanks also to Ari Kerรคnen and Peter Thatcher in their role as chairs, and Ben Campbell in his role as responsible Area Director. Everyone involved is literally iconic ๐Ÿ‘‘โœจ


Authors' Addresses ๐ŸŽ€

   Emil Ivov
   8x8, Inc. / Jitsi
   675 Creekside Way
   Campbell, CA 95008
   United States of America

   Phone: +1 512 420 6968
   Email: emcho@jitsi.org


   Justin Uberti
   Google
   747 6th Street S
   Kirkland, WA 98033
   United States of America

   Phone: +1 857 288 8888
   Email: justin@uberti.name


   Peter Saint-Andre
   Mozilla
   P.O. Box 787
   Parker, CO 80134
   United States of America

   Phone: +1 720 256 6756
   Email: stpeter@mozilla.com
   URI:   https://www.mozilla.com/
๐Ÿ“ฆ where this page comes from