summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYouness Alaoui <kakaroto@kakaroto.homelinux.net>2017-11-28 16:05:18 -0500
committerYouness Alaoui <kakaroto@kakaroto.homelinux.net>2017-11-28 16:45:38 -0500
commitfb2f1f77a31baa91968fc81c205f980b6913f403 (patch)
tree5aef44bf8030164dd4eb695106338cdfb6004791
parent4172d48852ecd1c86cc7bd4665b23697603d1eed (diff)
downloadlibnice-fb2f1f77a31baa91968fc81c205f980b6913f403.tar.gz
conncheck: handle alternate-server for turn relays differently
If a relay gives us an alternate-server, we need to cancel and reset every candidate discovery attempt that uses the same server, to avoid ending up with one component on one server and the other component on another server (causing relay candidates with mismatched foundations).
-rw-r--r--agent/conncheck.c56
1 files changed, 43 insertions, 13 deletions
diff --git a/agent/conncheck.c b/agent/conncheck.c
index 5b08311..c8a4edf 100644
--- a/agent/conncheck.c
+++ b/agent/conncheck.c
@@ -3592,6 +3592,41 @@ priv_add_new_turn_refresh (CandidateDiscovery *cdisco, NiceCandidate *relay_cand
return cand;
}
+static void priv_handle_turn_alternate_server (NiceAgent *agent,
+ CandidateDiscovery *disco, NiceAddress server, NiceAddress alternate)
+{
+ /* We need to cancel and reset all candidate discovery turn for the same
+ stream and type if there is an alternate server. Otherwise, we might end up
+ with two relay components on different servers, creating candidates with
+ unique foundations that only contain one component.
+ */
+ GSList *i;
+
+ for (i = agent->discovery_list; i; i = i->next) {
+ CandidateDiscovery *d = i->data;
+
+ if (!d->done &&
+ d->type == disco->type &&
+ d->stream == disco->stream &&
+ d->turn->type == disco->turn->type &&
+ nice_address_equal (&d->server, &server)) {
+ gchar ip[INET6_ADDRSTRLEN];
+ // Cancel the pending request to avoid a race condition with another
+ // component responding with another altenrate-server
+ d->stun_message.buffer = NULL;
+ d->stun_message.buffer_len = 0;
+
+ nice_address_to_string (&server, ip);
+ nice_debug ("Agent %p : Cancelling and setting alternate server %s for "
+ "CandidateDiscovery %p", agent, ip, d);
+ d->server = alternate;
+ d->turn->server = alternate;
+ d->pending = FALSE;
+ agent->discovery_unsched_items++;
+ }
+ }
+}
+
/*
* Tries to match STUN reply in 'buf' to an existing STUN discovery
* transaction. If found, a reply is sent.
@@ -3644,12 +3679,11 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
agent, d, (int)res);
if (res == STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER) {
- /* handle alternate server */
- nice_address_set_from_sockaddr (&d->server, &alternate.addr);
- nice_address_set_from_sockaddr (&d->turn->server, &alternate.addr);
+ NiceAddress addr;
- d->pending = FALSE;
- agent->discovery_unsched_items++;
+ /* handle alternate server */
+ nice_address_set_from_sockaddr (&addr, &alternate.addr);
+ priv_handle_turn_alternate_server (agent, d, d->server, addr);
} else if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS ||
res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) {
/* case: successful allocate, create a new local candidate */
@@ -3769,16 +3803,12 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
alternatelen != sizeof(alternate)) {
- NiceAddress alternate_addr;
-
- nice_address_set_from_sockaddr (&alternate_addr, &alternate.addr);
+ NiceAddress addr;
- if (!nice_address_equal (&alternate_addr, &d->server)) {
- nice_address_set_from_sockaddr (&d->server, &alternate.addr);
- nice_address_set_from_sockaddr (&d->turn->server, &alternate.addr);
+ nice_address_set_from_sockaddr (&addr, &alternate.addr);
- d->pending = FALSE;
- agent->discovery_unsched_items++;
+ if (!nice_address_equal (&addr, &d->server)) {
+ priv_handle_turn_alternate_server (agent, d, d->server, addr);
}
}
/* check for unauthorized error response */