Commit caf9f1d8 authored by Fabrice Bellet's avatar Fabrice Bellet Committed by Olivier Crête

agent: avoid leak of all turn refreshes when disposing the agent

With this patch we free all outstanding refreshes when the agent dispose
method is called, even those that are in the way to be discarded
asynchronously, when a stream is removed.

We also make the final user callback of the refresh proces synchronous,
so we don't have to deal with an heap use-after-free problem. This also
requires to order some parts of code.
parent e7b0b786
...@@ -3615,13 +3615,13 @@ nice_agent_remove_stream ( ...@@ -3615,13 +3615,13 @@ nice_agent_remove_stream (
/* note: remove items with matching stream_ids from both lists */ /* note: remove items with matching stream_ids from both lists */
conn_check_prune_stream (agent, stream); conn_check_prune_stream (agent, stream);
discovery_prune_stream (agent, stream_id); discovery_prune_stream (agent, stream_id);
refresh_prune_stream_async (agent, stream,
(NiceTimeoutLockedCallback) on_stream_refreshes_pruned);
agent->pruning_streams = g_slist_prepend (agent->pruning_streams, stream);
/* Remove the stream and signal its removal. */ /* Remove the stream and signal its removal. */
agent->streams = g_slist_remove (agent->streams, stream); agent->streams = g_slist_remove (agent->streams, stream);
agent->pruning_streams = g_slist_prepend (agent->pruning_streams, stream);
refresh_prune_stream_async (agent, stream,
(NiceTimeoutLockedCallback) on_stream_refreshes_pruned);
if (!agent->streams) if (!agent->streams)
priv_remove_keepalive_timer (agent); priv_remove_keepalive_timer (agent);
...@@ -5600,6 +5600,24 @@ nice_agent_dispose (GObject *object) ...@@ -5600,6 +5600,24 @@ nice_agent_dispose (GObject *object)
g_slist_free (agent->local_addresses); g_slist_free (agent->local_addresses);
agent->local_addresses = NULL; agent->local_addresses = NULL;
if (agent->refresh_list)
g_warning ("Agent %p : We still have alive TURN refreshes. Consider "
"using nice_agent_close_async() to prune them before releasing the "
"agent.", agent);
/* We must free refreshes before closing streams because a refresh
* callback data may contain a pointer to a stream to be freed, when
* previously called in the context of a stream removal, by
* refresh_prune_stream_async()
*/
for (i = agent->refresh_list; i;) {
GSList *next = i->next;
CandidateRefresh *refresh = i->data;
refresh_free (agent, refresh);
i = next;
}
while (agent->streams) { while (agent->streams) {
NiceStream *s = agent->streams->data; NiceStream *s = agent->streams->data;
...@@ -5624,20 +5642,6 @@ nice_agent_dispose (GObject *object) ...@@ -5624,20 +5642,6 @@ nice_agent_dispose (GObject *object)
free_queued_signal (sig); free_queued_signal (sig);
} }
if (agent->refresh_list)
g_warning ("Agent %p : We still have alive TURN refreshes. Consider "
"using nice_agent_close_async() to prune them before releasing the "
"agent.", agent);
for (i = agent->refresh_list; i;) {
GSList *next = i->next;
CandidateRefresh *refresh = i->data;
if (!refresh->disposing)
refresh_free (agent, refresh);
i = next;
}
g_free (agent->stun_server_ip); g_free (agent->stun_server_ip);
agent->stun_server_ip = NULL; agent->stun_server_ip = NULL;
......
...@@ -286,11 +286,7 @@ typedef struct { ...@@ -286,11 +286,7 @@ typedef struct {
static void on_refresh_removed (RefreshPruneAsyncData *data) static void on_refresh_removed (RefreshPruneAsyncData *data)
{ {
if (data->items_to_free == 0 || --(data->items_to_free) == 0) { if (data->items_to_free == 0 || --(data->items_to_free) == 0) {
GSource *timeout_source = NULL; data->cb (data->agent, data->user_data);
agent_timeout_add_with_context (data->agent, &timeout_source,
"Async refresh prune", 0, data->cb, data->user_data);
g_source_unref (timeout_source);
g_free (data); g_free (data);
} }
} }
......
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