|
|
|
|
@ -1086,20 +1086,20 @@ int ice_request(struct stream_fd *sfd, const endpoint_t *src,
|
|
|
|
|
atomic64_set(&ag->last_activity, rtpe_now.tv_sec);
|
|
|
|
|
|
|
|
|
|
/* determine candidate pair */
|
|
|
|
|
mutex_lock(&ag->lock);
|
|
|
|
|
|
|
|
|
|
cand = __cand_lookup(ag, src, ps->component);
|
|
|
|
|
{
|
|
|
|
|
LOCK(&ag->lock);
|
|
|
|
|
|
|
|
|
|
if (!cand)
|
|
|
|
|
pair = __learned_candidate(ag, sfd, src, attrs->priority);
|
|
|
|
|
else
|
|
|
|
|
pair = __pair_lookup(ag, cand, sfd->local_intf);
|
|
|
|
|
cand = __cand_lookup(ag, src, ps->component);
|
|
|
|
|
|
|
|
|
|
err = "Failed to determine ICE candidate from STUN request";
|
|
|
|
|
if (!pair)
|
|
|
|
|
goto err_unlock;
|
|
|
|
|
if (!cand)
|
|
|
|
|
pair = __learned_candidate(ag, sfd, src, attrs->priority);
|
|
|
|
|
else
|
|
|
|
|
pair = __pair_lookup(ag, cand, sfd->local_intf);
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&ag->lock);
|
|
|
|
|
err = "Failed to determine ICE candidate from STUN request";
|
|
|
|
|
if (!pair)
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!AGENT_ISSET(ag, LITE_SELF)) {
|
|
|
|
|
/* determine role conflict */
|
|
|
|
|
@ -1148,8 +1148,7 @@ int ice_request(struct stream_fd *sfd, const endpoint_t *src,
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
err_unlock:
|
|
|
|
|
mutex_unlock(&ag->lock);
|
|
|
|
|
err:
|
|
|
|
|
ilogs(ice, LOG_NOTICE | LOG_FLAG_LIMIT, "%s (from %s%s%s on interface %s)", err, FMT_M(endpoint_print_buf(src)),
|
|
|
|
|
endpoint_print_buf(&sfd->socket.local));
|
|
|
|
|
return 0;
|
|
|
|
|
@ -1197,15 +1196,15 @@ int ice_response(struct stream_fd *sfd, const endpoint_t *src,
|
|
|
|
|
|
|
|
|
|
atomic64_set(&ag->last_activity, rtpe_now.tv_sec);
|
|
|
|
|
|
|
|
|
|
mutex_lock(&ag->lock);
|
|
|
|
|
|
|
|
|
|
pair = g_hash_table_lookup(ag->transaction_hash, transaction);
|
|
|
|
|
err = "ICE/STUN response with unknown transaction received";
|
|
|
|
|
if (!pair)
|
|
|
|
|
goto err_unlock;
|
|
|
|
|
was_ctl = pair->was_controlling;
|
|
|
|
|
{
|
|
|
|
|
LOCK(&ag->lock);
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&ag->lock);
|
|
|
|
|
pair = g_hash_table_lookup(ag->transaction_hash, transaction);
|
|
|
|
|
err = "ICE/STUN response with unknown transaction received";
|
|
|
|
|
if (!pair)
|
|
|
|
|
goto err;
|
|
|
|
|
was_ctl = pair->was_controlling;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ifa = pair->local_intf;
|
|
|
|
|
|
|
|
|
|
@ -1239,65 +1238,63 @@ int ice_response(struct stream_fd *sfd, const endpoint_t *src,
|
|
|
|
|
/* we don't discover peer reflexive here (RFC 5245 7.1.3.2.1) as we don't expect to be behind NAT */
|
|
|
|
|
/* we also skip parts of 7.1.3.2.2 as we don't do server reflexive */
|
|
|
|
|
|
|
|
|
|
mutex_lock(&ag->lock);
|
|
|
|
|
{
|
|
|
|
|
LOCK(&ag->lock);
|
|
|
|
|
|
|
|
|
|
/* check if we're in the final (controlling) phase */
|
|
|
|
|
if (pair->was_nominated && PAIR_CLEAR(pair, TO_USE)) {
|
|
|
|
|
ilogs(ice, LOG_DEBUG, "Setting nominated ICE candidate pair "PAIR_FORMAT" as valid", PAIR_FMT(pair));
|
|
|
|
|
PAIR_SET(pair, VALID);
|
|
|
|
|
g_tree_insert_coll(ag->valid_pairs, pair, pair, __tree_coll_callback);
|
|
|
|
|
ret = __check_valid(ag);
|
|
|
|
|
goto out_unlock;
|
|
|
|
|
}
|
|
|
|
|
/* check if we're in the final (controlling) phase */
|
|
|
|
|
if (pair->was_nominated && PAIR_CLEAR(pair, TO_USE)) {
|
|
|
|
|
ilogs(ice, LOG_DEBUG, "Setting nominated ICE candidate pair "PAIR_FORMAT" as valid", PAIR_FMT(pair));
|
|
|
|
|
PAIR_SET(pair, VALID);
|
|
|
|
|
g_tree_insert_coll(ag->valid_pairs, pair, pair, __tree_coll_callback);
|
|
|
|
|
ret = __check_valid(ag);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PAIR_SET(pair, SUCCEEDED))
|
|
|
|
|
goto out_unlock;
|
|
|
|
|
if (PAIR_SET(pair, SUCCEEDED))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
ilogs(ice, LOG_DEBUG, "Setting ICE candidate pair "PAIR_FORMAT" as succeeded", PAIR_FMT(pair));
|
|
|
|
|
g_tree_insert_coll(ag->succeeded_pairs, pair, pair, __tree_coll_callback);
|
|
|
|
|
ilogs(ice, LOG_DEBUG, "Setting ICE candidate pair "PAIR_FORMAT" as succeeded", PAIR_FMT(pair));
|
|
|
|
|
g_tree_insert_coll(ag->succeeded_pairs, pair, pair, __tree_coll_callback);
|
|
|
|
|
|
|
|
|
|
if (!ag->start_nominating.tv_sec) {
|
|
|
|
|
if (__check_succeeded_complete(ag)) {
|
|
|
|
|
ag->start_nominating = rtpe_now;
|
|
|
|
|
timeval_add_usec(&ag->start_nominating, 100000);
|
|
|
|
|
__agent_schedule_abs(ag, &ag->start_nominating);
|
|
|
|
|
if (!ag->start_nominating.tv_sec) {
|
|
|
|
|
if (__check_succeeded_complete(ag)) {
|
|
|
|
|
ag->start_nominating = rtpe_now;
|
|
|
|
|
timeval_add_usec(&ag->start_nominating, 100000);
|
|
|
|
|
__agent_schedule_abs(ag, &ag->start_nominating);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* now unfreeze all other pairs from the same foundation */
|
|
|
|
|
for (component = 1; component <= MAX_COMPONENTS; component++) {
|
|
|
|
|
if (component == ps->component)
|
|
|
|
|
continue;
|
|
|
|
|
cand = __foundation_lookup(ag, &pair->remote_candidate->foundation, component);
|
|
|
|
|
if (!cand)
|
|
|
|
|
continue;
|
|
|
|
|
opair = __pair_lookup(ag, cand, ifa);
|
|
|
|
|
if (!opair)
|
|
|
|
|
continue;
|
|
|
|
|
/* now unfreeze all other pairs from the same foundation */
|
|
|
|
|
for (component = 1; component <= MAX_COMPONENTS; component++) {
|
|
|
|
|
if (component == ps->component)
|
|
|
|
|
continue;
|
|
|
|
|
cand = __foundation_lookup(ag, &pair->remote_candidate->foundation, component);
|
|
|
|
|
if (!cand)
|
|
|
|
|
continue;
|
|
|
|
|
opair = __pair_lookup(ag, cand, ifa);
|
|
|
|
|
if (!opair)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (PAIR_ISSET(opair, FAILED))
|
|
|
|
|
continue;
|
|
|
|
|
if (!PAIR_CLEAR(opair, FROZEN))
|
|
|
|
|
continue;
|
|
|
|
|
if (PAIR_ISSET(opair, FAILED))
|
|
|
|
|
continue;
|
|
|
|
|
if (!PAIR_CLEAR(opair, FROZEN))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ilogs(ice, LOG_DEBUG, "Unfreezing related ICE pair "PAIR_FORMAT, PAIR_FMT(opair));
|
|
|
|
|
}
|
|
|
|
|
ilogs(ice, LOG_DEBUG, "Unfreezing related ICE pair "PAIR_FORMAT, PAIR_FMT(opair));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if this was previously nominated by the peer, it's now valid */
|
|
|
|
|
if (PAIR_ISSET(pair, NOMINATED)) {
|
|
|
|
|
PAIR_SET(pair, VALID);
|
|
|
|
|
g_tree_insert_coll(ag->valid_pairs, pair, pair, __tree_coll_callback);
|
|
|
|
|
}
|
|
|
|
|
/* if this was previously nominated by the peer, it's now valid */
|
|
|
|
|
if (PAIR_ISSET(pair, NOMINATED)) {
|
|
|
|
|
PAIR_SET(pair, VALID);
|
|
|
|
|
g_tree_insert_coll(ag->valid_pairs, pair, pair, __tree_coll_callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = __check_valid(ag);
|
|
|
|
|
ret = __check_valid(ag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out_unlock:
|
|
|
|
|
mutex_unlock(&ag->lock);
|
|
|
|
|
out:
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
err_unlock:
|
|
|
|
|
mutex_unlock(&ag->lock);
|
|
|
|
|
err:
|
|
|
|
|
if (err)
|
|
|
|
|
ilogs(ice, LOG_NOTICE | LOG_FLAG_LIMIT, "%s (from %s%s%s on interface %s)",
|
|
|
|
|
|