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

conncheck: reorder some chunks of code

With this patch we simplify the levels of code indentation.

Differential Revision: https://phabricator.freedesktop.org/D1758
parent 5a42089a
...@@ -608,106 +608,106 @@ static gboolean priv_conn_check_tick_stream (NiceStream *stream, NiceAgent *agen ...@@ -608,106 +608,106 @@ static gboolean priv_conn_check_tick_stream (NiceStream *stream, NiceAgent *agen
gboolean keep_timer_going = FALSE; gboolean keep_timer_going = FALSE;
GSList *i; GSList *i;
CandidateCheckPair *pair; CandidateCheckPair *pair;
unsigned int timeout;
/* step: process ongoing STUN transactions */ /* step: process ongoing STUN transactions */
for (i = stream->conncheck_list; i ; i = i->next) { for (i = stream->conncheck_list; i ; i = i->next) {
CandidateCheckPair *p = i->data; CandidateCheckPair *p = i->data;
gchar tmpbuf1[INET6_ADDRSTRLEN], tmpbuf2[INET6_ADDRSTRLEN];
NiceComponent *component;
if (!agent_find_component (agent, p->stream_id, p->component_id,
NULL, &component))
continue;
if (p->state != NICE_CHECK_IN_PROGRESS)
continue;
if (p->state == NICE_CHECK_IN_PROGRESS) { if (p->stun_message.buffer == NULL) {
if (p->stun_message.buffer == NULL) { nice_debug ("Agent %p : STUN connectivity check was cancelled, marking as done.", agent);
nice_debug ("Agent %p : STUN connectivity check was cancelled, marking as done.", agent); p->state = NICE_CHECK_FAILED;
p->state = NICE_CHECK_FAILED; nice_debug ("Agent %p : pair %p state FAILED", agent, p);
nice_debug ("Agent %p : pair %p state FAILED", agent, p); continue;
} else if (priv_timer_expired (&p->next_tick, now)) { }
switch (stun_timer_refresh (&p->timer)) {
case STUN_USAGE_TIMER_RETURN_TIMEOUT:
{
gchar tmpbuf1[INET6_ADDRSTRLEN], tmpbuf2[INET6_ADDRSTRLEN];
NiceComponent *component;
if (!priv_timer_expired (&p->next_tick, now))
continue;
switch (stun_timer_refresh (&p->timer)) {
case STUN_USAGE_TIMER_RETURN_TIMEOUT:
timer_timeout: timer_timeout:
/* case: conncheck cancelled due to in-progress incoming /* case: conncheck cancelled due to in-progress incoming
* check, requeing the pair, ICE spec, sect 7.2.1.4 * check, requeing the pair, ICE spec, sect 7.2.1.4
* "Triggered Checks", "If the state of that pair is * "Triggered Checks", "If the state of that pair is
* In-Progress..." * In-Progress..."
*/ */
if (priv_conn_recheck_on_timeout (agent, p)) if (priv_conn_recheck_on_timeout (agent, p))
break; break;
/* case: error, abort processing */ /* case: error, abort processing */
nice_address_to_string (&p->local->addr, tmpbuf1); nice_address_to_string (&p->local->addr, tmpbuf1);
nice_address_to_string (&p->remote->addr, tmpbuf2); nice_address_to_string (&p->remote->addr, tmpbuf2);
nice_debug ("Agent %p : Retransmissions failed, giving up on connectivity check %p", agent, p); nice_debug ("Agent %p : Retransmissions failed, giving up on connectivity check %p", agent, p);
nice_debug ("Agent %p : Failed pair is [%s]:%u --> [%s]:%u", agent, nice_debug ("Agent %p : Failed pair is [%s]:%u --> [%s]:%u", agent,
tmpbuf1, nice_address_get_port (&p->local->addr), tmpbuf1, nice_address_get_port (&p->local->addr),
tmpbuf2, nice_address_get_port (&p->remote->addr)); tmpbuf2, nice_address_get_port (&p->remote->addr));
candidate_check_pair_fail (stream, agent, p); candidate_check_pair_fail (stream, agent, p);
priv_print_conn_check_lists (agent, G_STRFUNC, priv_print_conn_check_lists (agent, G_STRFUNC,
", retransmission failed"); ", retransmission failed");
/* perform a check if a transition state from connected to /* perform a check if a transition state from connected to
* ready can be performed. This may happen here, when the last * ready can be performed. This may happen here, when the last
* in-progress pair has expired its retransmission count * in-progress pair has expired its retransmission count
* in priv_conn_check_tick_stream(), which is a condition to * in priv_conn_check_tick_stream(), which is a condition to
* make the transition connected to ready. * make the transition connected to ready.
*/ */
if (agent_find_component (agent, p->stream_id, p->component_id, priv_update_check_list_state_for_ready (agent, stream, component);
NULL, &component)) break;
priv_update_check_list_state_for_ready (agent, stream, case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
component); timeout = stun_timer_remainder (&p->timer);
break;
}
case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
{
unsigned int timeout = stun_timer_remainder (&p->timer);
/* case: retransmission stopped, due to the nomination of /* case: retransmission stopped, due to the nomination of
* a pair with a higher priority than this in-progress pair, * a pair with a higher priority than this in-progress pair,
* ICE spec, sect 8.1.2 "Updating States", item 2.2 * ICE spec, sect 8.1.2 "Updating States", item 2.2
*/ */
if (!p->retransmit_on_timeout) if (!p->retransmit_on_timeout)
goto timer_timeout; goto timer_timeout;
/* case: conncheck cancelled due to in-progress incoming /* case: conncheck cancelled due to in-progress incoming
* check, requeing the pair, ICE spec, sect 7.2.1.4 * check, requeing the pair, ICE spec, sect 7.2.1.4
* "Triggered Checks", "If the state of that pair is * "Triggered Checks", "If the state of that pair is
* In-Progress..." * In-Progress..."
*/ */
if (priv_conn_recheck_on_timeout (agent, p)) if (priv_conn_recheck_on_timeout (agent, p))
break; break;
/* case: not ready, so schedule a new timeout */ /* case: not ready, so schedule a new timeout */
nice_debug ("Agent %p :STUN transaction retransmitted on pair %p " nice_debug ("Agent %p :STUN transaction retransmitted on pair %p "
"(timeout %dms, delay=%dms, retrans=%d).", "(timeout %dms, delay=%dms, retrans=%d).",
agent, p, timeout, p->timer.delay, p->timer.retransmissions); agent, p, timeout, p->timer.delay, p->timer.retransmissions);
agent_socket_send (p->sockptr, &p->remote->addr, agent_socket_send (p->sockptr, &p->remote->addr,
stun_message_length (&p->stun_message), stun_message_length (&p->stun_message),
(gchar *)p->stun_buffer); (gchar *)p->stun_buffer);
/* note: convert from milli to microseconds for g_time_val_add() */ /* note: convert from milli to microseconds for g_time_val_add() */
p->next_tick = *now; p->next_tick = *now;
g_time_val_add (&p->next_tick, timeout * 1000); g_time_val_add (&p->next_tick, timeout * 1000);
return TRUE; return TRUE;
} case STUN_USAGE_TIMER_RETURN_SUCCESS:
case STUN_USAGE_TIMER_RETURN_SUCCESS: timeout = stun_timer_remainder (&p->timer);
{
unsigned int timeout = stun_timer_remainder (&p->timer);
/* note: convert from milli to microseconds for g_time_val_add() */ /* note: convert from milli to microseconds for g_time_val_add() */
p->next_tick = *now; p->next_tick = *now;
g_time_val_add (&p->next_tick, timeout * 1000); g_time_val_add (&p->next_tick, timeout * 1000);
keep_timer_going = TRUE; keep_timer_going = TRUE;
break; break;
} default:
default: /* Nothing to do. */
/* Nothing to do. */ break;
break;
}
}
} }
} }
...@@ -2628,27 +2628,23 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair) ...@@ -2628,27 +2628,23 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) { if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
switch (agent->nomination_mode) { switch (agent->nomination_mode) {
case NICE_NOMINATION_MODE_REGULAR: case NICE_NOMINATION_MODE_REGULAR:
{ /* We are doing regular nomination, so we set the use-candidate
/* We are doing regular nomination, so we set the use-candidate * attrib, when the controlling agent decided which valid pair to
* attrib, when the controlling agent decided which valid pair to * resend with this flag in priv_conn_check_tick_stream()
* resend with this flag in priv_conn_check_tick_stream() */
*/ cand_use = pair->use_candidate_on_next_check;
cand_use = pair->use_candidate_on_next_check; nice_debug ("Agent %p : %s: set cand_use=%d "
nice_debug ("Agent %p : %s: set cand_use=%d " "(regular nomination).", agent, G_STRFUNC, cand_use);
"(regular nomination).", agent, G_STRFUNC, cand_use); break;
break;
}
case NICE_NOMINATION_MODE_AGGRESSIVE: case NICE_NOMINATION_MODE_AGGRESSIVE:
{ /* We are doing aggressive nomination, we set the use-candidate
/* We are doing aggressive nomination, we set the use-candidate * attrib in every check we send, when we are the controlling
* attrib in every check we send, when we are the controlling * agent, RFC 5245, 8.1.1.2
* agent, RFC 5245, 8.1.1.2 */
*/ cand_use = controlling;
cand_use = controlling; nice_debug ("Agent %p : %s: set cand_use=%d "
nice_debug ("Agent %p : %s: set cand_use=%d " "(aggressive nomination).", agent, G_STRFUNC, cand_use);
"(aggressive nomination).", agent, G_STRFUNC, cand_use); break;
break;
}
default: default:
/* Nothing to do. */ /* Nothing to do. */
break; break;
...@@ -2656,107 +2652,105 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair) ...@@ -2656,107 +2652,105 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
} else if (cand_use) } else if (cand_use)
pair->nominated = controlling; pair->nominated = controlling;
if (uname_len > 0) { if (uname_len == 0) {
buffer_len = stun_usage_ice_conncheck_create (&component->stun_agent, nice_debug ("Agent %p: no credentials found, cancelling conncheck", agent);
&pair->stun_message, pair->stun_buffer, sizeof(pair->stun_buffer), pair->stun_message.buffer = NULL;
uname, uname_len, password, password_len, pair->stun_message.buffer_len = 0;
cand_use, controlling, pair->prflx_priority, return -1;
agent->tie_breaker, }
pair->local->foundation,
agent_to_ice_compatibility (agent));
nice_debug ("Agent %p: conncheck created %zd - %p", agent, buffer_len, buffer_len = stun_usage_ice_conncheck_create (&component->stun_agent,
pair->stun_message.buffer); &pair->stun_message, pair->stun_buffer, sizeof(pair->stun_buffer),
uname, uname_len, password, password_len,
cand_use, controlling, pair->prflx_priority,
agent->tie_breaker,
pair->local->foundation,
agent_to_ice_compatibility (agent));
if (agent->compatibility == NICE_COMPATIBILITY_MSN || nice_debug ("Agent %p: conncheck created %zd - %p", agent, buffer_len,
agent->compatibility == NICE_COMPATIBILITY_OC2007) { pair->stun_message.buffer);
g_free (password);
}
if (buffer_len > 0) { if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
if (nice_socket_is_reliable(pair->sockptr)) { agent->compatibility == NICE_COMPATIBILITY_OC2007) {
stun_timer_start_reliable(&pair->timer, agent->stun_reliable_timeout); g_free (password);
} else { }
StunTimer *timer = &pair->timer;
if (pair->recheck_on_timeout)
/* The pair recheck on timeout can easily cause repetitive rechecks in
* a ping-pong effect, if both peers with the same behaviour try to
* check the same pair almost simultaneously, and if the network rtt
* is greater than the initial timer rto. The reply to the initial
* stun request may arrive after the in-progress conncheck
* cancellation (described in RFC 5245, sect 7.2.1.4). Cancellation
* creates a new stun request, and forgets the initial one.
* The conncheck timer is restarted with the same initial value,
* so the same situation happens again later.
*
* We choose to avoid resetting the timer in such situation.
* After enough retransmissions, the timeout delay becomes
* longer than the rtt, and the stun reply can be handled.
*/
nice_debug("Agent %p : reusing timer of pair %p: %d/%d %d/%dms",
agent, pair,
timer->retransmissions, timer->max_retransmissions,
timer->delay - stun_timer_remainder (timer), timer->delay);
else
stun_timer_start (timer,
priv_compute_conncheck_timer (agent, stream),
agent->stun_max_retransmissions);
pair->recheck_on_timeout = FALSE;
}
/* TCP-ACTIVE candidate must create a new socket before sending if (buffer_len == 0) {
* by connecting to the peer. The new socket is stored in the candidate nice_debug ("Agent %p: buffer is empty, cancelling conncheck", agent);
* check pair, until we discover a new local peer reflexive */ pair->stun_message.buffer = NULL;
if (pair->sockptr->fileno == NULL && pair->stun_message.buffer_len = 0;
pair->sockptr->type != NICE_SOCKET_TYPE_UDP_TURN && return -1;
pair->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) { }
NiceStream *stream2 = NULL;
NiceComponent *component2 = NULL;
NiceSocket *new_socket;
if (agent_find_component (agent, pair->stream_id, pair->component_id,
&stream2, &component2)) {
new_socket = nice_tcp_active_socket_connect (pair->sockptr,
&pair->remote->addr);
if (new_socket) {
pair->sockptr = new_socket;
_priv_set_socket_tos (agent, pair->sockptr, stream2->tos);
if (agent->reliable) {
nice_socket_set_writable_callback (pair->sockptr,
_tcp_sock_is_writable, component2);
}
nice_component_attach_socket (component2, new_socket); if (nice_socket_is_reliable(pair->sockptr))
} stun_timer_start_reliable(&pair->timer, agent->stun_reliable_timeout);
} else {
} StunTimer *timer = &pair->timer;
/* send the conncheck */
agent_socket_send (pair->sockptr, &pair->remote->addr, if (pair->recheck_on_timeout)
buffer_len, (gchar *)pair->stun_buffer); /* The pair recheck on timeout can easily cause repetitive rechecks in
* a ping-pong effect, if both peers with the same behaviour try to
* check the same pair almost simultaneously, and if the network rtt
* is greater than the initial timer rto. The reply to the initial
* stun request may arrive after the in-progress conncheck
* cancellation (described in RFC 5245, sect 7.2.1.4). Cancellation
* creates a new stun request, and forgets the initial one.
* The conncheck timer is restarted with the same initial value,
* so the same situation happens again later.
*
* We choose to avoid resetting the timer in such situation.
* After enough retransmissions, the timeout delay becomes
* longer than the rtt, and the stun reply can be handled.
*/
nice_debug("Agent %p : reusing timer of pair %p: %d/%d %d/%dms",
agent, pair,
timer->retransmissions, timer->max_retransmissions,
timer->delay - stun_timer_remainder (timer), timer->delay);
else
stun_timer_start (timer,
priv_compute_conncheck_timer (agent, stream),
agent->stun_max_retransmissions);
pair->recheck_on_timeout = FALSE;
}
if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { /* TCP-ACTIVE candidate must create a new socket before sending
ms_ice2_legacy_conncheck_send (&pair->stun_message, pair->sockptr, * by connecting to the peer. The new socket is stored in the candidate
&pair->remote->addr); * check pair, until we discover a new local peer reflexive */
if (pair->sockptr->fileno == NULL &&
pair->sockptr->type != NICE_SOCKET_TYPE_UDP_TURN &&
pair->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
NiceStream *stream2 = NULL;
NiceComponent *component2 = NULL;
NiceSocket *new_socket;
if (agent_find_component (agent, pair->stream_id, pair->component_id,
&stream2, &component2)) {
new_socket = nice_tcp_active_socket_connect (pair->sockptr,
&pair->remote->addr);
if (new_socket) {
pair->sockptr = new_socket;
_priv_set_socket_tos (agent, pair->sockptr, stream2->tos);
if (agent->reliable)
nice_socket_set_writable_callback (pair->sockptr,
_tcp_sock_is_writable, component2);
nice_component_attach_socket (component2, new_socket);
} }
timeout = stun_timer_remainder (&pair->timer);
/* note: convert from milli to microseconds for g_time_val_add() */
g_get_current_time (&pair->next_tick);
g_time_val_add (&pair->next_tick, timeout * 1000);
} else {
nice_debug ("Agent %p: buffer is empty, cancelling conncheck", agent);
pair->stun_message.buffer = NULL;
pair->stun_message.buffer_len = 0;
return -1;
} }
} else {
nice_debug ("Agent %p: no credentials found, cancelling conncheck", agent);
pair->stun_message.buffer = NULL;
pair->stun_message.buffer_len = 0;
return -1;
} }
/* send the conncheck */
agent_socket_send (pair->sockptr, &pair->remote->addr,
buffer_len, (gchar *)pair->stun_buffer);
if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2)
ms_ice2_legacy_conncheck_send (&pair->stun_message, pair->sockptr,
&pair->remote->addr);
timeout = stun_timer_remainder (&pair->timer);
/* note: convert from milli to microseconds for g_time_val_add() */
g_get_current_time (&pair->next_tick);
g_time_val_add (&pair->next_tick, timeout * 1000);
return 0; return 0;
} }
...@@ -2876,74 +2870,74 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *str ...@@ -2876,74 +2870,74 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *str
nice_debug ("Agent %p : Found a matching pair %p (%s) (state=%c) ...", nice_debug ("Agent %p : Found a matching pair %p (%s) (state=%c) ...",
agent, p, p->foundation, priv_state_to_gchar (p->state)); agent, p, p->foundation, priv_state_to_gchar (p->state));
if (p->state == NICE_CHECK_WAITING || switch (p->state) {
p->state == NICE_CHECK_FROZEN) { case NICE_CHECK_WAITING:
nice_debug ("Agent %p : pair %p added for a triggered check.", case NICE_CHECK_FROZEN:
agent, p); nice_debug ("Agent %p : pair %p added for a triggered check.",
priv_add_pair_to_triggered_check_queue (agent, p);
}
else if (p->state == NICE_CHECK_IN_PROGRESS) {
/* note: according to ICE SPEC sect 7.2.1.4 "Triggered Checks"
* we cancel the in-progress transaction, and after the
* retransmission timeout, we create a new connectivity check
* for that pair. The controlling role of this new check may
* be different from the role of this cancelled check.
*
* note: the flag retransmit_on_timeout unset means that
* another pair, with a higher priority is already nominated,
* so there's no reason to recheck this pair, since it can in
* no way replace the nominated one.
*/
if (!nice_socket_is_reliable (p->sockptr)) {
if (p->retransmit_on_timeout) {
nice_debug ("Agent %p : pair %p will be rechecked "
"on stun timer timeout.", agent, p);
/* this flag will determine the action at the retransmission
* timeout of the stun timer
*/
p->recheck_on_timeout = TRUE;
} else
nice_debug ("Agent %p : pair %p won't be retransmitted.",
agent, p);
}
}
else if (p->state == NICE_CHECK_SUCCEEDED) {
nice_debug ("Agent %p : nothing to do for pair %p.", agent, p);
/* note: this is a bit unsure corner-case -- let's do the
same state update as for processing responses to our own checks */
/* note: this update is required by the dribble test, to
* ensure the transition ready -> connected -> ready, because
* an incoming stun request generates a discovered peer reflexive,
* that causes the ready -> connected transition.
*/
priv_update_check_list_state_for_ready (agent, stream, component);
} else if (p->state == NICE_CHECK_FAILED) {
/* 7.2.1.4 Triggered Checks
* If the state of the pair is Failed, it is changed to Waiting
* and the agent MUST create a new connectivity check for that
* pair (representing a new STUN Binding request transaction), by
* enqueueing the pair in the triggered check queue.
*
* note: the flag retransmit_on_timeout unset means that
* another pair, with a higher priority is already nominated,
* we apply the same strategy than with an in-progress pair
* above.
*/
if (p->retransmit_on_timeout) {
nice_debug ("Agent %p : pair %p added for a triggered check.",
agent, p); agent, p);
priv_add_pair_to_triggered_check_queue (agent, p); priv_add_pair_to_triggered_check_queue (agent, p);
/* If the component for this pair is in failed state, move it break;
* back to connecting, and reinitiate the timers case NICE_CHECK_IN_PROGRESS:
/* note: according to ICE SPEC sect 7.2.1.4 "Triggered Checks"
* we cancel the in-progress transaction, and after the
* retransmission timeout, we create a new connectivity check
* for that pair. The controlling role of this new check may
* be different from the role of this cancelled check.
*
* note: the flag retransmit_on_timeout unset means that
* another pair, with a higher priority is already nominated,
* so there's no reason to recheck this pair, since it can in
* no way replace the nominated one.
*/ */
if (component->state == NICE_COMPONENT_STATE_FAILED) { if (!nice_socket_is_reliable (p->sockptr) &&
agent_signal_component_state_change (agent, stream->id, p->retransmit_on_timeout) {
component->id, NICE_COMPONENT_STATE_CONNECTING); nice_debug ("Agent %p : pair %p will be rechecked "
conn_check_schedule_next (agent); "on stun timer timeout.", agent, p);
/* this flag will determine the action at the retransmission
* timeout of the stun timer
*/
p->recheck_on_timeout = TRUE;
} }
} else break;
nice_debug ("Agent %p : pair %p won't be retransmitted.", case NICE_CHECK_SUCCEEDED:
agent, p); nice_debug ("Agent %p : nothing to do for pair %p.", agent, p);
/* note: this is a bit unsure corner-case -- let's do the
same state update as for processing responses to our own checks */
/* note: this update is required by the dribble test, to
* ensure the transition ready -> connected -> ready, because
* an incoming stun request generates a discovered peer reflexive,
* that causes the ready -> connected transition.
*/
priv_update_check_list_state_for_ready (agent, stream, component);
break;
case NICE_CHECK_FAILED:
/* 7.2.1.4 Triggered Checks
* If the state of the pair is Failed, it is changed to Waiting
* and the agent MUST create a new connectivity check for that
* pair (representing a new STUN Binding request transaction), by
* enqueueing the pair in the triggered check queue.
*
* note: the flag retransmit_on_timeout unset means that
* another pair, with a higher priority is already nominated,
* we apply the same strategy than with an in-progress pair
* above.
*/
if (p->retransmit_on_timeout) {
nice_debug ("Agent %p : pair %p added for a triggered check.",
agent, p);
priv_add_pair_to_triggered_check_queue (agent, p);
/* If the component for this pair is in failed state, move it
* back to connecting, and reinitiate the timers
*/
if (component->state == NICE_COMPONENT_STATE_FAILED) {
agent_signal_component_state_change (agent, stream->id,
component->id, NICE_COMPONENT_STATE_CONNECTING);
conn_check_schedule_next (agent);
}
}
break;
default:
break;
} }
/* note: the spec says the we SHOULD retransmit in-progress /* note: the spec says the we SHOULD retransmit in-progress
...@@ -3271,208 +3265,200 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, NiceStre ...@@ -3271,208 +3265,200 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, NiceStre
socklen_t socklen = sizeof (sockaddr); socklen_t socklen = sizeof (sockaddr);
GSList *i; GSList *i;
StunUsageIceReturn res; StunUsageIceReturn res;
gboolean trans_found = FALSE;
StunTransactionId discovery_id; StunTransactionId discovery_id;
StunTransactionId response_id; StunTransactionId response_id;
stun_message_id (resp, response_id); stun_message_id (resp, response_id);
for (i = stream->conncheck_list; i && trans_found != TRUE; i = i->next) { for (i = stream->conncheck_list; i; i = i->next) {
CandidateCheckPair *p = i->data; CandidateCheckPair *p = i->data;
if (p->stun_message.buffer) { if (p->stun_message.buffer == NULL)
stun_message_id (&p->stun_message, discovery_id); continue;
if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)) == 0) { stun_message_id (&p->stun_message, discovery_id);
res = stun_usage_ice_conncheck_process (resp,
&sockaddr.storage, &socklen,
agent_to_ice_compatibility (agent));
nice_debug ("Agent %p : stun_bind_process/conncheck for %p res %d "
"(controlling=%d).", agent, p, (int)res, agent->controlling_mode);
if (res == STUN_USAGE_ICE_RETURN_SUCCESS ||
res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
/* case: found a matching connectivity check request */
CandidateCheckPair *ok_pair = NULL;
nice_debug ("Agent %p : conncheck %p MATCHED.", agent, p);
p->stun_message.buffer = NULL;
p->stun_message.buffer_len = 0;
/* step: verify that response came from the same IP address we
* sent the original request to (see 7.1.2.1. "Failure
* Cases") */
if (nice_address_equal (from, &p->remote->addr) != TRUE) {
p->state = NICE_CHECK_FAILED;
if (nice_debug_is_enabled ()) {
gchar tmpbuf[INET6_ADDRSTRLEN];
gchar tmpbuf2[INET6_ADDRSTRLEN];
nice_debug ("Agent %p : conncheck %p FAILED"
" (mismatch of source address).", agent, p);
nice_address_to_string (&p->remote->addr, tmpbuf);
nice_address_to_string (from, tmpbuf2);
nice_debug ("Agent %p : '%s:%u' != '%s:%u'", agent,
tmpbuf, nice_address_get_port (&p->remote->addr),
tmpbuf2, nice_address_get_port (from));
}
trans_found = TRUE;
break;
}
/* note: CONNECTED but not yet READY, see docs */ if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)))
continue;
/* step: handle the possible case of a peer-reflexive
* candidate where the mapped-address in response does
* not match any local candidate, see 7.1.2.2.1
* "Discovering Peer Reflexive Candidates" ICE ID-19) */
if (res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
/* note: this is same as "adding to VALID LIST" in the spec
text */
p->state = NICE_CHECK_SUCCEEDED;
p->valid = TRUE;
g_assert_not_reached ();
nice_debug ("Agent %p : Mapped address not found."
" conncheck %p SUCCEEDED.", agent, p);
nice_component_add_valid_candidate (component, p->remote);
} else {
ok_pair = priv_process_response_check_for_reflexive (agent,
stream, component, p, sockptr, &sockaddr.addr,
local_candidate, remote_candidate);
}
/* note: The success of this check might also res = stun_usage_ice_conncheck_process (resp,
* cause the state of other checks to change as well, ICE &sockaddr.storage, &socklen,
* spec 7.1.3.2.3 agent_to_ice_compatibility (agent));
*/ nice_debug ("Agent %p : stun_bind_process/conncheck for %p res %d "
priv_conn_check_unfreeze_related (agent, stream, p); "(controlling=%d).", agent, p, (int)res, agent->controlling_mode);
/* Note: this assignment helps to reduce the numbers of cases if (res == STUN_USAGE_ICE_RETURN_SUCCESS ||
* to be tested. If ok_pair and p refer to distinct pairs, it res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
* means that ok_pair is a discovered peer reflexive one, /* case: found a matching connectivity check request */
* caused by the check made on pair p. In that case, the
* flags to be tested are on p, but the nominated flag will be CandidateCheckPair *ok_pair = NULL;
* set on ok_pair. When there's no discovered pair, p and
* ok_pair refer to the same pair. nice_debug ("Agent %p : conncheck %p MATCHED.", agent, p);
* To summarize : p is a SUCCEEDED pair, ok_pair is a p->stun_message.buffer = NULL;
* DISCOVERED, VALID, and eventually NOMINATED pair. p->stun_message.buffer_len = 0;
*/
if (!ok_pair) /* step: verify that response came from the same IP address we
ok_pair = p; * sent the original request to (see 7.1.2.1. "Failure
* Cases") */
/* step: updating nominated flag (ICE 7.1.2.2.4 "Updating the if (nice_address_equal (from, &p->remote->addr) == FALSE) {
Nominated Flag" (ID-19) */
if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) { p->state = NICE_CHECK_FAILED;
nice_debug ("Agent %p : Updating nominated flag (%s): " if (nice_debug_is_enabled ()) {
"ok_pair=%p (%d/%d) p=%p (%d/%d) (ucnc/mnora)", gchar tmpbuf[INET6_ADDRSTRLEN];
agent, p->local->transport == NICE_CANDIDATE_TRANSPORT_UDP ? gchar tmpbuf2[INET6_ADDRSTRLEN];
"UDP" : "TCP", nice_debug ("Agent %p : conncheck %p FAILED"
ok_pair, ok_pair->use_candidate_on_next_check, " (mismatch of source address).", agent, p);
ok_pair->mark_nominated_on_response_arrival, nice_address_to_string (&p->remote->addr, tmpbuf);
p, p->use_candidate_on_next_check, nice_address_to_string (from, tmpbuf2);
p->mark_nominated_on_response_arrival); nice_debug ("Agent %p : '%s:%u' != '%s:%u'", agent,
tmpbuf, nice_address_get_port (&p->remote->addr),
if (agent->controlling_mode) { tmpbuf2, nice_address_get_port (from));
switch (agent->nomination_mode) { }
case NICE_NOMINATION_MODE_REGULAR: return TRUE;
if (p->use_candidate_on_next_check) { }
nice_debug ("Agent %p : marking pair %p (%s) as nominated "
"(regular nomination, control=1, " /* note: CONNECTED but not yet READY, see docs */
"use_cand_on_next_check=1).",
agent, ok_pair, ok_pair->foundation); /* step: handle the possible case of a peer-reflexive
ok_pair->nominated = TRUE; * candidate where the mapped-address in response does
} * not match any local candidate, see 7.1.2.2.1
break; * "Discovering Peer Reflexive Candidates" ICE ID-19) */
case NICE_NOMINATION_MODE_AGGRESSIVE:
if (!p->nominated) { if (res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
nice_debug ("Agent %p : marking pair %p (%s) as nominated " p->state = NICE_CHECK_SUCCEEDED;
"(aggressive nomination, control=1).", p->valid = TRUE;
agent, ok_pair, ok_pair->foundation); nice_debug ("Agent %p : Mapped address not found."
ok_pair->nominated = TRUE; " conncheck %p SUCCEEDED.", agent, p);
} nice_component_add_valid_candidate (component, p->remote);
break; } else
default: ok_pair = priv_process_response_check_for_reflexive (agent,
/* Nothing to do */ stream, component, p, sockptr, &sockaddr.addr,
break; local_candidate, remote_candidate);
/* note: The success of this check might also
* cause the state of other checks to change as well, ICE
* spec 7.1.3.2.3
*/
priv_conn_check_unfreeze_related (agent, stream, p);
/* Note: this assignment helps to reduce the numbers of cases
* to be tested. If ok_pair and p refer to distinct pairs, it
* means that ok_pair is a discovered peer reflexive one,
* caused by the check made on pair p. In that case, the
* flags to be tested are on p, but the nominated flag will be
* set on ok_pair. When there's no discovered pair, p and
* ok_pair refer to the same pair.
* To summarize : p is a SUCCEEDED pair, ok_pair is a
* DISCOVERED, VALID, and eventually NOMINATED pair.
*/
if (!ok_pair)
ok_pair = p;
/* step: updating nominated flag (ICE 7.1.2.2.4 "Updating the
Nominated Flag" (ID-19) */
if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
nice_debug ("Agent %p : Updating nominated flag (%s): "
"ok_pair=%p (%d/%d) p=%p (%d/%d) (ucnc/mnora)",
agent, p->local->transport == NICE_CANDIDATE_TRANSPORT_UDP ?
"UDP" : "TCP",
ok_pair, ok_pair->use_candidate_on_next_check,
ok_pair->mark_nominated_on_response_arrival,
p, p->use_candidate_on_next_check,
p->mark_nominated_on_response_arrival);
if (agent->controlling_mode) {
switch (agent->nomination_mode) {
case NICE_NOMINATION_MODE_REGULAR:
if (p->use_candidate_on_next_check) {
nice_debug ("Agent %p : marking pair %p (%s) as nominated "
"(regular nomination, control=1, "
"use_cand_on_next_check=1).",
agent, ok_pair, ok_pair->foundation);
ok_pair->nominated = TRUE;
} }
} else { break;
if (p->mark_nominated_on_response_arrival) { case NICE_NOMINATION_MODE_AGGRESSIVE:
if (!p->nominated) {
nice_debug ("Agent %p : marking pair %p (%s) as nominated " nice_debug ("Agent %p : marking pair %p (%s) as nominated "
"(%s nomination, control=0, mark_on_response=1).", "(aggressive nomination, control=1).",
agent, ok_pair, ok_pair->foundation, agent, ok_pair, ok_pair->foundation);
agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE ?
"aggressive" : "regular");
ok_pair->nominated = TRUE; ok_pair->nominated = TRUE;
} }
} break;
default:
/* Nothing to do */
break;
} }
} else {
if (ok_pair->nominated == TRUE) { if (p->mark_nominated_on_response_arrival) {
priv_update_selected_pair (agent, component, ok_pair); nice_debug ("Agent %p : marking pair %p (%s) as nominated "
priv_print_conn_check_lists (agent, G_STRFUNC, "(%s nomination, control=0, mark_on_response=1).",
", got a nominated pair"); agent, ok_pair, ok_pair->foundation,
agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE ?
/* Do not step down to CONNECTED if we're already at state READY*/ "aggressive" : "regular");
if (component->state != NICE_COMPONENT_STATE_READY) { ok_pair->nominated = TRUE;
/* step: notify the client of a new component state (must be done
* before the possible check list state update step */
agent_signal_component_state_change (agent,
stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
}
} }
}
}
/* step: update pair states (ICE 7.1.2.2.3 "Updating pair if (ok_pair->nominated == TRUE) {
states" and 8.1.2 "Updating States", ID-19) */ priv_update_selected_pair (agent, component, ok_pair);
priv_update_check_list_state_for_ready (agent, stream, component); priv_print_conn_check_lists (agent, G_STRFUNC,
", got a nominated pair");
trans_found = TRUE; /* Do not step down to CONNECTED if we're already at state READY*/
} else if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) { if (component->state != NICE_COMPONENT_STATE_READY)
/* case: role conflict error, need to restart with new role */ /* step: notify the client of a new component state (must be done
nice_debug ("Agent %p : conncheck %p ROLE CONFLICT, restarting", agent, p); * before the possible check list state update step */
agent_signal_component_state_change (agent,
/* note: this res value indicates that the role of the peer stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
* agent has not changed after the tie-breaker comparison, so }
* this is our role that must change. see ICE sect. 7.1.3.1
* "Failure Cases". Our role might already have changed due to
* an earlier incoming request, but if not, change role now.
*
* Sect. 7.1.3.1 is not clear on this point, but we choose to
* put the candidate pair in the triggered check list even
* when the agent did not switch its role. The reason for this
* interpretation is that the reception of the stun reply, even
* an error reply, is a good sign that this pair will be
* valid, if we retry the check after the role of both peers
* has been fixed.
*/
if (p->stun_message.buffer != NULL) { /* step: update pair states (ICE 7.1.2.2.3 "Updating pair
guint64 tie; states" and 8.1.2 "Updating States", ID-19) */
gboolean controlled_mode; priv_update_check_list_state_for_ready (agent, stream, component);
} else if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) {
/* case: role conflict error, need to restart with new role */
nice_debug ("Agent %p : conncheck %p ROLE CONFLICT, restarting", agent, p);
/* note: this res value indicates that the role of the peer
* agent has not changed after the tie-breaker comparison, so
* this is our role that must change. see ICE sect. 7.1.3.1
* "Failure Cases". Our role might already have changed due to
* an earlier incoming request, but if not, change role now.
*
* Sect. 7.1.3.1 is not clear on this point, but we choose to
* put the candidate pair in the triggered check list even
* when the agent did not switch its role. The reason for this
* interpretation is that the reception of the stun reply, even
* an error reply, is a good sign that this pair will be
* valid, if we retry the check after the role of both peers
* has been fixed.
*/
controlled_mode = (stun_message_find64 (&p->stun_message, if (p->stun_message.buffer != NULL) {
STUN_ATTRIBUTE_ICE_CONTROLLED, &tie) == guint64 tie;
STUN_MESSAGE_RETURN_SUCCESS); gboolean controlled_mode;
priv_check_for_role_conflict (agent, controlled_mode); controlled_mode = (stun_message_find64 (&p->stun_message,
STUN_ATTRIBUTE_ICE_CONTROLLED, &tie) ==
STUN_MESSAGE_RETURN_SUCCESS);
p->stun_message.buffer = NULL; priv_check_for_role_conflict (agent, controlled_mode);
p->stun_message.buffer_len = 0;
priv_add_pair_to_triggered_check_queue (agent, p); p->stun_message.buffer = NULL;
} p->stun_message.buffer_len = 0;
trans_found = TRUE; priv_add_pair_to_triggered_check_queue (agent, p);
} else {
/* case: STUN error, the check STUN context was freed */
nice_debug ("Agent %p : conncheck %p FAILED.", agent, p);
p->stun_message.buffer = NULL;
p->stun_message.buffer_len = 0;
trans_found = TRUE;
}
} }
} else {
/* case: STUN error, the check STUN context was freed */
nice_debug ("Agent %p : conncheck %p FAILED.", agent, p);
p->stun_message.buffer = NULL;
p->stun_message.buffer_len = 0;
} }
return TRUE;
} }
return trans_found; return FALSE;
} }
/* /*
......
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