Commit f6337b53 authored by Philip Withnall's avatar Philip Withnall

agent: Remove dangling pointers on NiceSocket destruction

If a NiceSocket is destroyed, various pointers are currently left
dangling to it in the conncheck state. These can cause crashes if (for
example) a CandidateCheckPair with such a dangling pointer is then used;
the GSocket methods will fail.

Fix this by explicitly removing the socket and all NiceCandidates which
wrap it from various areas of the state.
parent 6c8856bb
......@@ -184,6 +184,9 @@ component_clean_turn_servers (Component *cmp)
if (candidate == cmp->selected_pair.local) {
if (cmp->turn_candidate) {
refresh_prune_candidate (cmp->agent, cmp->turn_candidate);
discovery_prune_socket (cmp->agent, cmp->turn_candidate->sockptr);
conn_check_prune_socket (cmp->agent, cmp->stream, cmp,
cmp->turn_candidate->sockptr);
component_detach_socket (cmp, cmp->turn_candidate->sockptr);
nice_candidate_free (cmp->turn_candidate);
}
......@@ -194,6 +197,9 @@ component_clean_turn_servers (Component *cmp)
cmp->turn_candidate = candidate;
} else {
refresh_prune_candidate (cmp->agent, candidate);
discovery_prune_socket (cmp->agent, candidate->sockptr);
conn_check_prune_socket (cmp->agent, cmp->stream, cmp,
candidate->sockptr);
component_detach_socket (cmp, candidate->sockptr);
nice_candidate_free (candidate);
}
......@@ -385,6 +391,10 @@ void component_update_selected_pair (Component *component, const CandidatePair *
if (component->selected_pair.local &&
component->selected_pair.local == component->turn_candidate) {
refresh_prune_candidate (component->agent, component->turn_candidate);
discovery_prune_socket (component->agent,
component->turn_candidate->sockptr);
conn_check_prune_socket (component->agent, component->stream, component,
component->turn_candidate->sockptr);
component_detach_socket (component, component->turn_candidate->sockptr);
nice_candidate_free (component->turn_candidate);
component->turn_candidate = NULL;
......@@ -561,6 +571,20 @@ component_detach_socket (Component *component, NiceSocket *nicesock)
nice_debug ("Detach socket %p.", nicesock);
/* Remove the socket from various lists. */
for (l = component->incoming_checks; l != NULL;) {
IncomingCheck *icheck = l->data;
GSList *next = l->next;
if (icheck->local_socket == nicesock) {
component->incoming_checks =
g_slist_delete_link (component->incoming_checks, l);
incoming_check_free (icheck);
}
l = next;
}
/* Find the SocketSource for the socket. */
l = g_slist_find_custom (component->socket_sources, nicesock,
_find_socket_source);
......
......@@ -3281,3 +3281,33 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
return TRUE;
}
/* Remove all pointers to the given @sock from the connection checking process.
* These are entirely NiceCandidates pointed to from various places. */
void
conn_check_prune_socket (NiceAgent *agent, Stream *stream, Component *component,
NiceSocket *sock)
{
GSList *l;
if (component->selected_pair.local &&
component->selected_pair.local->sockptr == sock &&
component->state == NICE_COMPONENT_STATE_READY) {
nice_debug ("Agent %p: Selected pair socket %p has been destroyed, "
"declaring failed", agent, sock);
agent_signal_component_state_change (agent,
stream->id, component->id, NICE_COMPONENT_STATE_FAILED);
}
/* Prune from the candidate check pairs. */
for (l = stream->conncheck_list; l != NULL; l = l->next) {
CandidateCheckPair *p = l->data;
if ((p->local != NULL && p->local->sockptr == sock) ||
(p->remote != NULL && p->remote->sockptr == sock)) {
nice_debug ("Agent %p : Retransmissions failed, giving up on "
"connectivity check %p", agent, p);
candidate_check_pair_fail (stream, agent, p);
}
}
}
......@@ -104,5 +104,8 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream, Compo
gint conn_check_compare (const CandidateCheckPair *a, const CandidateCheckPair *b);
void conn_check_remote_candidates_set(NiceAgent *agent);
NiceCandidateTransport conn_check_match_transport (NiceCandidateTransport transport);
void
conn_check_prune_socket (NiceAgent *agent, Stream *stream, Component *component,
NiceSocket *sock);
#endif /*_NICE_CONNCHECK_H */
......@@ -124,6 +124,33 @@ void discovery_prune_stream (NiceAgent *agent, guint stream_id)
}
}
/*
* Prunes the list of discovery processes for items related
* to socket @sock.
*
* @return TRUE on success, FALSE on a fatal error
*/
void discovery_prune_socket (NiceAgent *agent, NiceSocket *sock)
{
GSList *i;
for (i = agent->discovery_list; i ; ) {
CandidateDiscovery *discovery = i->data;
GSList *next = i->next;
if (discovery->nicesock == sock) {
agent->discovery_list = g_slist_remove (agent->discovery_list, discovery);
discovery_free_item (discovery);
}
i = next;
}
if (agent->discovery_list == NULL) {
/* noone using the timer anymore, clean it up */
discovery_free (agent);
}
}
/*
* Frees the CandidateDiscovery structure pointed to
......@@ -248,6 +275,23 @@ void refresh_prune_candidate (NiceAgent *agent, NiceCandidate *candidate)
}
}
void refresh_prune_socket (NiceAgent *agent, NiceSocket *sock)
{
GSList *i;
for (i = agent->refresh_list; i;) {
GSList *next = i->next;
CandidateRefresh *refresh = i->data;
if (refresh->nicesock == sock) {
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,
......
......@@ -85,11 +85,13 @@ 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_prune_socket (NiceAgent *agent, NiceSocket *sock);
void refresh_cancel (CandidateRefresh *refresh);
void discovery_free (NiceAgent *agent);
void discovery_prune_stream (NiceAgent *agent, guint stream_id);
void discovery_prune_socket (NiceAgent *agent, NiceSocket *sock);
void discovery_schedule (NiceAgent *agent);
typedef enum {
......
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