discovery: use the address of a relayed candidate for its foundation
authorFabrice Bellet <fabrice@bellet.info>
Thu, 16 Apr 2020 18:09:59 +0000 (20:09 +0200)
committerOlivier CrĂȘte <olivier.crete@ocrete.ca>
Mon, 14 Dec 2020 19:35:52 +0000 (19:35 +0000)
According to the RFC, the base address of a relayed candidate is that
candidate itself. This precision is interesting and not just
anecdotical, since it allows the relayed candidates from the same turn
server to share the same foundation, and to not be tested concurrently.

However, since the base address in its current form is required to
compute a unique priority, we choose the keep the
candidate->base_address for this purpose, and to apply the RFC
consequence about relay candidate base being equal to the candidate
itself in the foundation assignment instead.

agent/discovery.c

index a16df08..dc28291 100644 (file)
@@ -514,32 +514,51 @@ static void priv_assign_foundation (NiceAgent *agent, NiceCandidate *candidate)
       for (k = component->local_candidates; k; k = k->next) {
        NiceCandidateImpl *n = k->data;
 
-        /* note: candidate must not on the local candidate list */
+        /* note: candidate must not be on the local candidate list */
        g_assert (c != n);
 
-       if (candidate->type == n->c.type &&
-            candidate->transport == n->c.transport &&
-           nice_address_equal_no_port (&candidate->base_addr, &n->c.base_addr) &&
-            (candidate->type != NICE_CANDIDATE_TYPE_RELAYED ||
-                priv_compare_turn_servers (c->turn, n->turn)) &&
-            !(agent->compatibility == NICE_COMPATIBILITY_GOOGLE &&
-                n->c.type == NICE_CANDIDATE_TYPE_RELAYED)) {
+       if (candidate->type != n->c.type)
+          continue;
+
+        if (candidate->transport != n->c.transport)
+          continue;
+
+        if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED &&
+           !nice_address_equal_no_port (&candidate->addr, &n->c.addr))
+          continue;
+
+        /* The base of a relayed candidate is that candidate itself, see
+         * sect 5.1.1.2. (Server Reflexive and Relayed Candidates) or
+         * ICE spec (RFC8445). It allows the relayed candidate from the
+         * same TURN server to share the same foundation.
+         */
+        if (candidate->type != NICE_CANDIDATE_TYPE_RELAYED &&
+            !nice_address_equal_no_port (&candidate->base_addr, &n->c.base_addr))
+          continue;
+
+        if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED &&
+            !priv_compare_turn_servers (c->turn, n->turn))
+          continue;
+
+        if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED &&
+            agent->compatibility == NICE_COMPATIBILITY_GOOGLE)
          /* note: currently only one STUN server per stream at a
           *       time is supported, so there is no need to check
           *       for candidates that would otherwise share the
           *       foundation, but have different STUN servers */
-         g_strlcpy (candidate->foundation, n->c.foundation,
-              NICE_CANDIDATE_MAX_FOUNDATION);
-          if (n->c.username) {
-            g_free (candidate->username);
-            candidate->username = g_strdup (n->c.username);
-          }
-          if (n->c.password) {
-            g_free (candidate->password);
-            candidate->password = g_strdup (n->c.password);
-          }
-         return;
-       }
+          continue;
+
+       g_strlcpy (candidate->foundation, n->c.foundation,
+            NICE_CANDIDATE_MAX_FOUNDATION);
+        if (n->c.username) {
+          g_free (candidate->username);
+          candidate->username = g_strdup (n->c.username);
+        }
+        if (n->c.password) {
+          g_free (candidate->password);
+          candidate->password = g_strdup (n->c.password);
+        }
+       return;
       }
     }
   }