Commit cadf5118 authored by Fabrice Bellet's avatar Fabrice Bellet

conncheck: better handle remote tcp disconnection

With this patch, we handle tcp disconnections in a more robust way.
Such disconnections cause the underlying socket to be detached, and
various related pairs have to be discarded from the conncheck list.
This may cause unexpected behaviour, like a previously connected
component to come back in state connecting, if the selected pair
is concerned by a tcp disconnection for example.
parent 804a4c09
...@@ -2557,7 +2557,10 @@ void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, gui ...@@ -2557,7 +2557,10 @@ void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, gui
TRANSITION (FAILED, GATHERING) || TRANSITION (FAILED, GATHERING) ||
/* Possible by calling set_remote_candidates() without calling /* Possible by calling set_remote_candidates() without calling
* nice_agent_gather_candidates(): */ * nice_agent_gather_candidates(): */
TRANSITION (DISCONNECTED, CONNECTING)); TRANSITION (DISCONNECTED, CONNECTING) ||
/* If a tcp socket of connected pair is disconnected, in
* conn_check_prune_socket(): */
TRANSITION (CONNECTED, CONNECTING));
#undef TRANSITION #undef TRANSITION
......
...@@ -185,11 +185,8 @@ nice_component_remove_socket (NiceAgent *agent, NiceComponent *cmp, ...@@ -185,11 +185,8 @@ nice_component_remove_socket (NiceAgent *agent, NiceComponent *cmp,
continue; continue;
} }
if (candidate == cmp->selected_pair.local) { if (candidate == cmp->selected_pair.local)
nice_component_clear_selected_pair (cmp); nice_component_clear_selected_pair (cmp);
agent_signal_component_state_change (agent, cmp->stream_id,
cmp->id, NICE_COMPONENT_STATE_FAILED);
}
refresh_prune_candidate (agent, candidate); refresh_prune_candidate (agent, candidate);
if (candidate->sockptr != nsocket && stream) { if (candidate->sockptr != nsocket && stream) {
...@@ -217,11 +214,8 @@ nice_component_remove_socket (NiceAgent *agent, NiceComponent *cmp, ...@@ -217,11 +214,8 @@ nice_component_remove_socket (NiceAgent *agent, NiceComponent *cmp,
continue; continue;
} }
if (candidate == cmp->selected_pair.remote) { if (candidate == cmp->selected_pair.remote)
nice_component_clear_selected_pair (cmp); nice_component_clear_selected_pair (cmp);
agent_signal_component_state_change (agent, cmp->stream_id,
cmp->id, NICE_COMPONENT_STATE_FAILED);
}
if (stream) if (stream)
conn_check_prune_socket (agent, stream, cmp, candidate->sockptr); conn_check_prune_socket (agent, stream, cmp, candidate->sockptr);
......
...@@ -4852,14 +4852,20 @@ conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *co ...@@ -4852,14 +4852,20 @@ conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *co
{ {
GSList *l; GSList *l;
gboolean pair_failed = FALSE; gboolean pair_failed = FALSE;
gboolean selected_pair_failed = FALSE;
guint p_nominated = 0, p_count = 0;
if (component->selected_pair.local && if (component->selected_pair.local &&
component->selected_pair.local->sockptr == sock && component->selected_pair.local->sockptr == sock) {
component->state == NICE_COMPONENT_STATE_READY) {
nice_debug ("Agent %p: Selected pair socket %p has been destroyed, " nice_debug ("Agent %p: Selected pair socket %p has been destroyed, "
"declaring failed", agent, sock); "declaring failed", agent, sock);
selected_pair_failed = TRUE;
if (component->state == NICE_COMPONENT_STATE_READY)
agent_signal_component_state_change (agent, agent_signal_component_state_change (agent,
stream->id, component->id, NICE_COMPONENT_STATE_FAILED); stream->id, component->id, NICE_COMPONENT_STATE_FAILED);
else if (component->state == NICE_COMPONENT_STATE_CONNECTED)
agent_signal_component_state_change (agent,
stream->id, component->id, NICE_COMPONENT_STATE_CONNECTING);
} }
/* Prune from the candidate check pairs. */ /* Prune from the candidate check pairs. */
...@@ -4867,20 +4873,45 @@ conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *co ...@@ -4867,20 +4873,45 @@ conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *co
CandidateCheckPair *p = l->data; CandidateCheckPair *p = l->data;
GSList *next = l->next; GSList *next = l->next;
if (p->component_id != component->id) {
l = next;
continue;
}
if (selected_pair_failed && !p->retransmit && p->stun_transactions)
p->retransmit = TRUE;
if ((p->local != NULL && ((NiceCandidateImpl*) p->local)->sockptr == sock) || if ((p->local != NULL && ((NiceCandidateImpl*) p->local)->sockptr == sock) ||
(p->remote != NULL && ((NiceCandidateImpl*)p->remote)->sockptr == sock) || (p->remote != NULL && ((NiceCandidateImpl*)p->remote)->sockptr == sock) ||
(p->sockptr == sock)) { (p->sockptr == sock)) {
nice_debug ("Agent %p : Retransmissions failed, giving up on pair %p", nice_debug ("Agent %p : Retransmissions failed, giving up on pair %p",
agent, p); agent, p);
if (component->selected_pair.local == ((NiceCandidateImpl *)p->local) &&
component->selected_pair.remote == ((NiceCandidateImpl *)p->remote))
selected_pair_failed = TRUE;
candidate_check_pair_fail (stream, agent, p); candidate_check_pair_fail (stream, agent, p);
candidate_check_pair_free (agent, p); candidate_check_pair_free (agent, p);
stream->conncheck_list = g_slist_delete_link (stream->conncheck_list, l); stream->conncheck_list = g_slist_delete_link (stream->conncheck_list, l);
pair_failed = TRUE; pair_failed = TRUE;
} else {
p_count++;
if (p->nominated)
p_nominated++;
} }
l = next; l = next;
} }
if (pair_failed) {
if (p_count == 0)
agent_signal_component_state_change (agent,
stream->id, component->id, NICE_COMPONENT_STATE_FAILED);
else if (p_nominated == 0 &&
component->state >= NICE_COMPONENT_STATE_CONNECTED)
agent_signal_component_state_change (agent,
stream->id, component->id, NICE_COMPONENT_STATE_CONNECTING);
}
/* outside of the previous loop, because it may /* outside of the previous loop, because it may
* remove pairs from the conncheck list * remove pairs from the conncheck list
*/ */
......
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