Commit 69749bad authored by Olivier Crête's avatar Olivier Crête

component: Clear turn local candidates when clearing turn servers

But keep the turn connection that's currently being used if it is
the selected candidate. Also clear the TURN candidate refresh.
parent 8ccbd8f0
......@@ -51,6 +51,7 @@
#include "debug.h"
#include "component.h"
#include "discovery.h"
#include "agent-priv.h"
......@@ -148,9 +149,48 @@ component_new (guint id, NiceAgent *agent, Stream *stream)
void
component_clean_turn_servers (Component *cmp)
{
GSList *i;
g_list_free_full (cmp->turn_servers, (GDestroyNotify) turn_server_unref);
cmp->turn_servers = NULL;
for (i = cmp->local_candidates; i;) {
NiceCandidate *candidate = i->data;
GSList *next = i->next;
if (candidate->type != NICE_CANDIDATE_TYPE_RELAYED) {
i = next;
continue;
}
/* note: do not remove the remote candidate that is
* currently part of the 'selected pair', see ICE
* 9.1.1.1. "ICE Restarts" (ID-19)
*
* So what we do instead is that we put the selected candidate
* in a special location and keep it "alive" that way. This is
* especially important for TURN, because refresh requests to the
* server need to keep happening.
*/
if (candidate == cmp->selected_pair.local) {
if (cmp->turn_candidate) {
refresh_prune_candidate (cmp->agent, cmp->turn_candidate);
component_detach_socket (cmp, cmp->turn_candidate->sockptr);
nice_candidate_free (cmp->turn_candidate);
}
/* Bring the priority down to 0, so that it will be replaced
* on the new run.
*/
cmp->selected_pair.priority = 0;
cmp->turn_candidate = candidate;
} else {
refresh_prune_candidate (cmp->agent, candidate);
component_detach_socket (cmp, candidate->sockptr);
nice_candidate_free (candidate);
}
cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i);
i = next;
}
}
void
......@@ -174,6 +214,10 @@ component_free (Component *cmp)
nice_candidate_free (cmp->restart_candidate),
cmp->restart_candidate = NULL;
if (cmp->turn_candidate)
nice_candidate_free (cmp->turn_candidate),
cmp->turn_candidate = NULL;
for (i = cmp->incoming_checks; i; i = i->next) {
IncomingCheck *icheck = i->data;
g_free (icheck->username);
......@@ -181,9 +225,12 @@ component_free (Component *cmp)
}
g_slist_free (cmp->local_candidates);
cmp->local_candidates = NULL;
g_slist_free (cmp->remote_candidates);
cmp->remote_candidates = NULL;
component_free_socket_sources (cmp);
g_slist_free (cmp->incoming_checks);
cmp->incoming_checks = NULL;
component_clean_turn_servers (cmp);
......@@ -285,7 +332,7 @@ component_restart (Component *cmp)
for (i = cmp->remote_candidates; i; i = i->next) {
NiceCandidate *candidate = i->data;
/* note: do not remove the remote candidate that is
/* note: do not remove the local candidate that is
* currently part of the 'selected pair', see ICE
* 9.1.1.1. "ICE Restarts" (ID-19) */
if (candidate == cmp->selected_pair.remote) {
......
......@@ -149,7 +149,7 @@ struct _Component
CandidatePair selected_pair; /**< independent from checklists,
see ICE 11.1. "Sending Media" (ID-19) */
NiceCandidate *restart_candidate; /**< for storing active remote candidate during a restart */
NiceCandidate *turn_candidate; /**< for storing active turn candidate if turn servers have been cleared */
/* I/O handling. The main context must always be non-NULL, and is used for all
* socket recv() operations. All io_callback emissions are invoked in this
* context too.
......
......@@ -1128,6 +1128,14 @@ static gboolean priv_update_selected_pair (NiceAgent *agent, Component *componen
component->selected_pair.keepalive.tick_source = NULL;
}
if (component->selected_pair.local &&
component->selected_pair.local == component->turn_candidate) {
refresh_prune_candidate (agent, component->turn_candidate);
component_detach_socket (component, component->turn_candidate->sockptr);
nice_candidate_free (component->turn_candidate);
component->turn_candidate = NULL;
}
memset (&component->selected_pair, 0, sizeof(CandidatePair));
component->selected_pair.local = pair->local;
component->selected_pair.remote = pair->remote;
......
......@@ -218,6 +218,9 @@ void refresh_prune_stream (NiceAgent *agent, guint stream_id)
CandidateRefresh *cand = i->data;
GSList *next = i->next;
/* Don't free the candidate refresh to the currently selected local candidate
* unless the whole pair is being destroyed.
*/
if (cand->stream->id == stream_id) {
agent->refresh_list = g_slist_delete_link (agent->refresh_list, i);
refresh_free_item (cand);
......@@ -228,6 +231,23 @@ void refresh_prune_stream (NiceAgent *agent, guint stream_id)
}
void refresh_prune_candidate (NiceAgent *agent, NiceCandidate *candidate)
{
GSList *i;
for (i = agent->refresh_list; i;) {
GSList *next = i->next;
CandidateRefresh *refresh = i->data;
if (refresh->candidate == candidate) {
agent->refresh_list = g_slist_delete_link (agent->refresh_list, i);
refresh_free_item (refresh);
}
i = next;
}
}
void refresh_cancel (CandidateRefresh *refresh)
{
refresh->agent->refresh_list = g_slist_remove (refresh->agent->refresh_list,
......@@ -235,6 +255,7 @@ void refresh_cancel (CandidateRefresh *refresh)
refresh_free_item (refresh);
}
/*
* Adds a new local candidate. Implements the candidate pruning
* defined in ICE spec section 4.1.3 "Eliminating Redundant
......
......@@ -84,6 +84,7 @@ typedef struct
void refresh_free (NiceAgent *agent);
void refresh_prune_stream (NiceAgent *agent, guint stream_id);
void refresh_prune_candidate (NiceAgent *agent, NiceCandidate *candidate);
void refresh_cancel (CandidateRefresh *refresh);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment