2017-04-19 07:56:45 +00:00
/*
Copyright ( c ) 2007 , Adobe Systems , Incorporated
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are
met :
* Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
* Neither the name of Adobe Systems , Network Resonance nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
" AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
static char * RCSSTRING __UNUSED__ = " $Id: ice_candidate_pair.c,v 1.2 2008/04/28 17:59:01 ekr Exp $ " ;
# include <assert.h>
# include <string.h>
# include <nr_api.h>
# include "async_timer.h"
# include "ice_ctx.h"
# include "ice_util.h"
# include "ice_codeword.h"
# include "stun.h"
static char * nr_ice_cand_pair_states [ ] = { " UNKNOWN " , " FROZEN " , " WAITING " , " IN_PROGRESS " , " FAILED " , " SUCCEEDED " , " CANCELLED " } ;
static void nr_ice_candidate_pair_restart_stun_role_change_cb ( NR_SOCKET s , int how , void * cb_arg ) ;
static void nr_ice_candidate_pair_compute_codeword ( nr_ice_cand_pair * pair ,
nr_ice_candidate * lcand , nr_ice_candidate * rcand ) ;
int nr_ice_candidate_pair_create ( nr_ice_peer_ctx * pctx , nr_ice_candidate * lcand , nr_ice_candidate * rcand , nr_ice_cand_pair * * pairp )
{
nr_ice_cand_pair * pair = 0 ;
UINT8 o_priority , a_priority ;
int r , _status ;
UINT4 RTO ;
nr_ice_candidate tmpcand ;
UINT8 t_priority ;
if ( ! ( pair = RCALLOC ( sizeof ( nr_ice_cand_pair ) ) ) )
ABORT ( R_NO_MEMORY ) ;
pair - > pctx = pctx ;
nr_ice_candidate_pair_compute_codeword ( pair , lcand , rcand ) ;
if ( r = nr_concat_strings ( & pair - > as_string , pair - > codeword , " | " , lcand - > addr . as_string , " | " ,
rcand - > addr . as_string , " ( " , lcand - > label , " | " , rcand - > label , " ) " , NULL ) )
ABORT ( r ) ;
nr_ice_candidate_pair_set_state ( pctx , pair , NR_ICE_PAIR_STATE_FROZEN ) ;
pair - > local = lcand ;
pair - > remote = rcand ;
/* Priority computation S 5.7.2 */
if ( pctx - > ctx - > flags & NR_ICE_CTX_FLAGS_OFFERER )
{
assert ( ! ( pctx - > ctx - > flags & NR_ICE_CTX_FLAGS_ANSWERER ) ) ;
o_priority = lcand - > priority ;
a_priority = rcand - > priority ;
}
else {
o_priority = rcand - > priority ;
a_priority = lcand - > priority ;
}
pair - > priority = ( MIN ( o_priority , a_priority ) ) < < 32 |
( MAX ( o_priority , a_priority ) ) < < 1 | ( o_priority > a_priority ? 0 : 1 ) ;
/*
TODO ( bcampen @ mozilla . com ) : Would be nice to log why this candidate was
created ( initial pair generation , triggered check , and new trickle
candidate seem to be the possibilities here ) .
*/
r_log ( LOG_ICE , LOG_INFO , " ICE(%s)/CAND-PAIR(%s): Pairing candidate %s (%x):%s (%x) priority=%llu (%llx) " , pctx - > ctx - > label , pair - > codeword , lcand - > addr . as_string , lcand - > priority , rcand - > addr . as_string , rcand - > priority , pair - > priority , pair - > priority ) ;
/* Foundation */
if ( r = nr_concat_strings ( & pair - > foundation , lcand - > foundation , " | " ,
rcand - > foundation , NULL ) )
ABORT ( r ) ;
/* Compute the RTO per S 16 */
RTO = MAX ( 100 , ( pctx - > ctx - > Ta * pctx - > waiting_pairs ) ) ;
/* Make a bogus candidate to compute a theoretical peer reflexive
* priority per S 7.1 .1 .1 */
memcpy ( & tmpcand , lcand , sizeof ( tmpcand ) ) ;
tmpcand . type = PEER_REFLEXIVE ;
if ( r = nr_ice_candidate_compute_priority ( & tmpcand ) )
ABORT ( r ) ;
t_priority = tmpcand . priority ;
/* Our sending context */
if ( r = nr_stun_client_ctx_create ( pair - > as_string ,
lcand - > osock ,
& rcand - > addr , RTO , & pair - > stun_client ) )
ABORT ( r ) ;
if ( ! ( pair - > stun_client - > params . ice_binding_request . username = r_strdup ( rcand - > stream - > l2r_user ) ) )
ABORT ( R_NO_MEMORY ) ;
if ( r = r_data_copy ( & pair - > stun_client - > params . ice_binding_request . password ,
& rcand - > stream - > l2r_pass ) )
ABORT ( r ) ;
pair - > stun_client - > params . ice_binding_request . priority = t_priority ;
/* TODO(ekr@rtfm.com): Do we need to frob this when we change role. Bug 890667 */
pair - > stun_client - > params . ice_binding_request . control = pctx - > controlling ?
NR_ICE_CONTROLLING : NR_ICE_CONTROLLED ;
pair - > stun_client - > params . ice_binding_request . priority = t_priority ;
pair - > stun_client - > params . ice_binding_request . tiebreaker = pctx - > tiebreaker ;
* pairp = pair ;
_status = 0 ;
abort :
if ( _status ) {
nr_ice_candidate_pair_destroy ( & pair ) ;
}
return ( _status ) ;
}
int nr_ice_candidate_pair_destroy ( nr_ice_cand_pair * * pairp )
{
nr_ice_cand_pair * pair ;
if ( ! pairp | | ! * pairp )
return ( 0 ) ;
pair = * pairp ;
* pairp = 0 ;
RFREE ( pair - > as_string ) ;
RFREE ( pair - > foundation ) ;
nr_ice_socket_deregister ( pair - > local - > isock , pair - > stun_client_handle ) ;
if ( pair - > stun_client ) {
RFREE ( pair - > stun_client - > params . ice_binding_request . username ) ;
RFREE ( pair - > stun_client - > params . ice_binding_request . password . data ) ;
nr_stun_client_ctx_destroy ( & pair - > stun_client ) ;
}
NR_async_timer_cancel ( pair - > stun_cb_timer ) ;
NR_async_timer_cancel ( pair - > restart_role_change_cb_timer ) ;
NR_async_timer_cancel ( pair - > restart_nominated_cb_timer ) ;
RFREE ( pair ) ;
return ( 0 ) ;
}
int nr_ice_candidate_pair_unfreeze ( nr_ice_peer_ctx * pctx , nr_ice_cand_pair * pair )
{
assert ( pair - > state = = NR_ICE_PAIR_STATE_FROZEN ) ;
nr_ice_candidate_pair_set_state ( pctx , pair , NR_ICE_PAIR_STATE_WAITING ) ;
return ( 0 ) ;
}
static void nr_ice_candidate_pair_stun_cb ( NR_SOCKET s , int how , void * cb_arg )
{
int r , _status ;
nr_ice_cand_pair * pair = cb_arg , * orig_pair ;
nr_ice_candidate * cand = 0 ;
nr_stun_message * sres ;
nr_transport_addr * request_src ;
nr_transport_addr * request_dst ;
nr_transport_addr * response_src ;
nr_transport_addr response_dst ;
nr_stun_message_attribute * attr ;
pair - > stun_cb_timer = 0 ;
r_log ( LOG_ICE , LOG_DEBUG , " ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s): STUN cb on pair addr = %s " ,
pair - > pctx - > label , pair - > local - > stream - > label , pair - > codeword , pair - > as_string ) ;
/* This ordinarily shouldn't happen, but can if we're
doing the second check to confirm nomination .
Just bail out */
if ( pair - > state = = NR_ICE_PAIR_STATE_SUCCEEDED )
goto done ;
switch ( pair - > stun_client - > state ) {
case NR_STUN_CLIENT_STATE_FAILED :
sres = pair - > stun_client - > response ;
if ( sres & & nr_stun_message_has_attribute ( sres , NR_STUN_ATTR_ERROR_CODE , & attr ) & & attr - > u . error_code . number = = 487 ) {
/*
* Flip the controlling bit ; subsequent 487 s for other pairs will be
* ignored , since we abandon their STUN transactions .
*/
nr_ice_peer_ctx_switch_controlling_role ( pair - > pctx ) ;
return ;
}
/* Fall through */
case NR_STUN_CLIENT_STATE_TIMED_OUT :
nr_ice_candidate_pair_set_state ( pair - > pctx , pair , NR_ICE_PAIR_STATE_FAILED ) ;
break ;
case NR_STUN_CLIENT_STATE_DONE :
/* make sure the addresses match up S 7.1.2.2 */
response_src = & pair - > stun_client - > peer_addr ;
request_dst = & pair - > remote - > addr ;
if ( nr_transport_addr_cmp ( response_src , request_dst , NR_TRANSPORT_ADDR_CMP_MODE_ALL ) ) {
r_log ( LOG_ICE , LOG_WARNING , " ICE-PEER(%s)/CAND-PAIR(%s): Peer address mismatch %s != %s " , pair - > pctx - > label , pair - > codeword , response_src - > as_string , request_dst - > as_string ) ;
nr_ice_candidate_pair_set_state ( pair - > pctx , pair , NR_ICE_PAIR_STATE_FAILED ) ;
break ;
}
request_src = & pair - > stun_client - > my_addr ;
nr_socket_getaddr ( pair - > local - > osock , & response_dst ) ;
if ( nr_transport_addr_cmp ( request_src , & response_dst , NR_TRANSPORT_ADDR_CMP_MODE_ALL ) ) {
r_log ( LOG_ICE , LOG_WARNING , " ICE-PEER(%s)/CAND-PAIR(%s): Local address mismatch %s != %s " , pair - > pctx - > label , pair - > codeword , request_src - > as_string , response_dst . as_string ) ;
nr_ice_candidate_pair_set_state ( pair - > pctx , pair , NR_ICE_PAIR_STATE_FAILED ) ;
break ;
}
if ( strlen ( pair - > stun_client - > results . ice_binding_response . mapped_addr . as_string ) = = 0 ) {
/* we're using the mapped_addr returned by the server to lookup our
* candidate , but if the server fails to do that we can ' t perform
* the lookup - - this may be a BUG because if we ' ve gotten here
* then the transaction ID check succeeded , and perhaps we should
* just assume that it ' s the server we ' re talking to and that our
* peer is ok , but I ' m not sure how that ' ll interact with the
* peer reflexive logic below */
r_log ( LOG_ICE , LOG_WARNING , " ICE-PEER(%s)/CAND-PAIR(%s): server failed to return mapped address on pair %s " , pair - > pctx - > label , pair - > codeword , pair - > as_string ) ;
nr_ice_candidate_pair_set_state ( pair - > pctx , pair , NR_ICE_PAIR_STATE_FAILED ) ;
break ;
}
else if ( ! nr_transport_addr_cmp ( & pair - > local - > addr , & pair - > stun_client - > results . ice_binding_response . mapped_addr , NR_TRANSPORT_ADDR_CMP_MODE_ALL ) ) {
nr_ice_candidate_pair_set_state ( pair - > pctx , pair , NR_ICE_PAIR_STATE_SUCCEEDED ) ;
}
else if ( pair - > stun_client - > state = = NR_STUN_CLIENT_STATE_DONE ) {
/* OK, this didn't correspond to a pair on the check list, but
it probably matches one of our candidates */
cand = TAILQ_FIRST ( & pair - > local - > component - > candidates ) ;
while ( cand ) {
if ( ! nr_transport_addr_cmp ( & cand - > addr , & pair - > stun_client - > results . ice_binding_response . mapped_addr , NR_TRANSPORT_ADDR_CMP_MODE_ALL ) )
break ;
cand = TAILQ_NEXT ( cand , entry_comp ) ;
}
/* OK, nothing found, must be peer reflexive */
if ( ! cand ) {
if ( pair - > pctx - > ctx - > flags & NR_ICE_CTX_FLAGS_RELAY_ONLY ) {
/* Any STUN response with a reflexive address in it is unwanted
when we ' ll send on relay only . Bail since cand is used below . */
goto done ;
}
if ( r = nr_ice_candidate_create ( pair - > pctx - > ctx ,
pair - > local - > component , pair - > local - > isock , pair - > local - > osock ,
PEER_REFLEXIVE , pair - > local - > tcp_type , 0 , pair - > local - > component - > component_id , & cand ) )
ABORT ( r ) ;
if ( r = nr_transport_addr_copy ( & cand - > addr , & pair - > stun_client - > results . ice_binding_response . mapped_addr ) )
ABORT ( r ) ;
cand - > state = NR_ICE_CAND_STATE_INITIALIZED ;
TAILQ_INSERT_TAIL ( & pair - > local - > component - > candidates , cand , entry_comp ) ;
}
/* Note: we stomp the existing pair! */
orig_pair = pair ;
if ( r = nr_ice_candidate_pair_create ( pair - > pctx , cand , pair - > remote ,
& pair ) )
ABORT ( r ) ;
nr_ice_candidate_pair_set_state ( pair - > pctx , pair , NR_ICE_PAIR_STATE_SUCCEEDED ) ;
if ( r = nr_ice_component_insert_pair ( pair - > remote - > component , pair ) )
ABORT ( r ) ;
/* If the original pair was nominated, make us nominated,
since we replace him */
if ( orig_pair - > peer_nominated )
pair - > peer_nominated = 1 ;
/* Now mark the orig pair failed */
nr_ice_candidate_pair_set_state ( orig_pair - > pctx , orig_pair , NR_ICE_PAIR_STATE_FAILED ) ;
}
/* Should we set nominated? */
if ( pair - > pctx - > controlling ) {
if ( pair - > pctx - > ctx - > flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION )
pair - > nominated = 1 ;
}
else {
if ( pair - > peer_nominated )
pair - > nominated = 1 ;
}
/* increment the number of valid pairs in the component */
/* We don't bother to maintain a separate valid list */
pair - > remote - > component - > valid_pairs + + ;
/* S 7.1.2.2: unfreeze other pairs with the same foundation*/
if ( r = nr_ice_media_stream_unfreeze_pairs_foundation ( pair - > remote - > stream , pair - > foundation ) )
ABORT ( r ) ;
/* Deal with this pair being nominated */
if ( pair - > nominated ) {
if ( r = nr_ice_component_nominated_pair ( pair - > remote - > component , pair ) )
ABORT ( r ) ;
}
break ;
default :
ABORT ( R_INTERNAL ) ;
}
/* If we're controlling but in regular mode, ask the handler
if he wants to nominate something and stop . . . */
if ( pair - > pctx - > controlling & & ! ( pair - > pctx - > ctx - > flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION ) ) {
if ( r = nr_ice_component_select_pair ( pair - > pctx , pair - > remote - > component ) ) {
if ( r ! = R_NOT_FOUND )
ABORT ( r ) ;
}
}
done :
_status = 0 ;
abort :
return ;
}
static void nr_ice_candidate_pair_restart ( nr_ice_peer_ctx * pctx , nr_ice_cand_pair * pair )
{
int r , _status ;
UINT4 mode ;
nr_ice_candidate_pair_set_state ( pctx , pair , NR_ICE_PAIR_STATE_IN_PROGRESS ) ;
/* Start STUN */
if ( pair - > pctx - > controlling & & ( pair - > pctx - > ctx - > flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION ) )
mode = NR_ICE_CLIENT_MODE_USE_CANDIDATE ;
else
mode = NR_ICE_CLIENT_MODE_BINDING_REQUEST ;
nr_stun_client_reset ( pair - > stun_client ) ;
if ( r = nr_stun_client_start ( pair - > stun_client , mode , nr_ice_candidate_pair_stun_cb , pair ) )
ABORT ( r ) ;
if ( ( r = nr_ice_ctx_remember_id ( pair - > pctx - > ctx , pair - > stun_client - > request ) ) ) {
/* ignore if this fails (which it shouldn't) because it's only an
* optimization and the cleanup routines are not going to do the right
* thing if this fails */
assert ( 0 ) ;
}
_status = 0 ;
abort :
if ( _status ) {
/* Don't fire the CB, but schedule it to fire ASAP */
assert ( ! pair - > stun_cb_timer ) ;
NR_ASYNC_TIMER_SET ( 0 , nr_ice_candidate_pair_stun_cb , pair , & pair - > stun_cb_timer ) ;
_status = 0 ;
}
}
int nr_ice_candidate_pair_start ( nr_ice_peer_ctx * pctx , nr_ice_cand_pair * pair )
{
int r , _status ;
/* Register the stun ctx for when responses come in*/
if ( r = nr_ice_socket_register_stun_client ( pair - > local - > isock , pair - > stun_client , & pair - > stun_client_handle ) )
ABORT ( r ) ;
nr_ice_candidate_pair_restart ( pctx , pair ) ;
_status = 0 ;
abort :
return ( _status ) ;
}
static int nr_ice_candidate_copy_for_triggered_check ( nr_ice_cand_pair * pair )
{
int r , _status ;
nr_ice_cand_pair * copy ;
if ( r = nr_ice_candidate_pair_create ( pair - > pctx , pair - > local , pair - > remote , & copy ) )
ABORT ( r ) ;
/* Preserve nomination status */
copy - > peer_nominated = pair - > peer_nominated ;
copy - > nominated = pair - > nominated ;
r_log ( LOG_ICE , LOG_INFO , " CAND-PAIR(%s): Adding pair to check list and trigger check queue: %s " , pair - > codeword , pair - > as_string ) ;
2020-06-17 03:18:17 +00:00
nr_ice_candidate_pair_insert ( & pair - > remote - > stream - > check_list , copy ) ;
2017-04-19 07:56:45 +00:00
nr_ice_candidate_pair_trigger_check_append ( & pair - > remote - > stream - > trigger_check_queue , copy ) ;
copy - > triggered = 1 ;
nr_ice_candidate_pair_set_state ( copy - > pctx , copy , NR_ICE_PAIR_STATE_WAITING ) ;
_status = 0 ;
abort :
return ( _status ) ;
}
int nr_ice_candidate_pair_do_triggered_check ( nr_ice_peer_ctx * pctx , nr_ice_cand_pair * pair )
{
int r , _status ;
if ( pair - > state = = NR_ICE_PAIR_STATE_CANCELLED ) {
r_log ( LOG_ICE , LOG_DEBUG , " ICE-PEER(%s)/CAND_PAIR(%s): Ignoring matching but canceled pair " , pctx - > label , pair - > codeword ) ;
return ( 0 ) ;
} else if ( pair - > state = = NR_ICE_PAIR_STATE_SUCCEEDED ) {
r_log ( LOG_ICE , LOG_DEBUG , " ICE-PEER(%s)/CAND_PAIR(%s): No new trigger check for succeeded pair " , pctx - > label , pair - > codeword ) ;
return ( 0 ) ;
}
/* Do not run this logic more than once on a given pair */
if ( ! pair - > triggered ) {
r_log ( LOG_ICE , LOG_INFO , " ICE-PEER(%s)/CAND-PAIR(%s): triggered check on %s " , pctx - > label , pair - > codeword , pair - > as_string ) ;
pair - > triggered = 1 ;
switch ( pair - > state ) {
case NR_ICE_PAIR_STATE_FAILED :
/* OK, there was a pair, it's just invalid: According to Section
* 7.2 .1 .4 , we need to resurrect it */
r_log ( LOG_ICE , LOG_INFO , " ICE-PEER(%s)/CAND-PAIR(%s): received STUN check on failed pair, resurrecting: %s " , pctx - > label , pair - > codeword , pair - > as_string ) ;
/* fall through */
case NR_ICE_PAIR_STATE_FROZEN :
nr_ice_candidate_pair_set_state ( pctx , pair , NR_ICE_PAIR_STATE_WAITING ) ;
/* fall through even further */
case NR_ICE_PAIR_STATE_WAITING :
/* Append it additionally to the trigger check queue */
r_log ( LOG_ICE , LOG_INFO , " ICE-PEER(%s)/CAND-PAIR(%s): Inserting pair to trigger check queue: %s " , pctx - > label , pair - > codeword , pair - > as_string ) ;
nr_ice_candidate_pair_trigger_check_append ( & pair - > remote - > stream - > trigger_check_queue , pair ) ;
break ;
case NR_ICE_PAIR_STATE_IN_PROGRESS :
/* Instead of trying to maintain two stun contexts on the same pair,
* and handling heterogenous responses and error conditions , we instead
* create a second pair that is identical except that it has the
* | triggered | bit set . We also cancel the original pair , but it can
* still succeed on its own in the special waiting state . */
if ( r = nr_ice_candidate_copy_for_triggered_check ( pair ) )
ABORT ( r ) ;
nr_ice_candidate_pair_cancel ( pair - > pctx , pair , 1 ) ;
break ;
default :
/* all states are handled - a new/unknown state should not
* automatically enter the start_checks ( ) below */
assert ( 0 ) ;
break ;
}
/* Ensure that the timers are running to start checks on the topmost entry
* of the triggered check queue . */
if ( r = nr_ice_media_stream_start_checks ( pair - > pctx , pair - > remote - > stream ) )
ABORT ( r ) ;
}
_status = 0 ;
abort :
return ( _status ) ;
}
int nr_ice_candidate_pair_cancel ( nr_ice_peer_ctx * pctx , nr_ice_cand_pair * pair , int move_to_wait_state )
{
if ( pair - > state ! = NR_ICE_PAIR_STATE_FAILED ) {
/* If it's already running we need to terminate the stun */
if ( pair - > state = = NR_ICE_PAIR_STATE_IN_PROGRESS ) {
if ( move_to_wait_state ) {
nr_stun_client_wait ( pair - > stun_client ) ;
} else {
nr_stun_client_cancel ( pair - > stun_client ) ;
}
}
nr_ice_candidate_pair_set_state ( pctx , pair , NR_ICE_PAIR_STATE_CANCELLED ) ;
}
return ( 0 ) ;
}
int nr_ice_candidate_pair_select ( nr_ice_cand_pair * pair )
{
int r , _status ;
if ( ! pair ) {
r_log ( LOG_ICE , LOG_ERR , " ICE-PAIR: No pair chosen " ) ;
ABORT ( R_BAD_ARGS ) ;
}
if ( pair - > state ! = NR_ICE_PAIR_STATE_SUCCEEDED ) {
r_log ( LOG_ICE , LOG_ERR , " ICE-PEER(%s)/CAND-PAIR(%s): tried to install non-succeeded pair, ignoring: %s " , pair - > pctx - > label , pair - > codeword , pair - > as_string ) ;
}
else {
/* Ok, they chose one */
/* 1. Send a new request with nominated. Do it as a scheduled
event to avoid reentrancy issues . Only do this if it hasn ' t
happened already ( though this shouldn ' t happen . )
*/
if ( ! pair - > restart_nominated_cb_timer )
NR_ASYNC_TIMER_SET ( 0 , nr_ice_candidate_pair_restart_stun_nominated_cb , pair , & pair - > restart_nominated_cb_timer ) ;
/* 2. Tell ourselves this pair is ready */
if ( r = nr_ice_component_nominated_pair ( pair - > remote - > component , pair ) )
ABORT ( r ) ;
}
_status = 0 ;
abort :
return ( _status ) ;
}
int nr_ice_candidate_pair_set_state ( nr_ice_peer_ctx * pctx , nr_ice_cand_pair * pair , int state )
{
int r , _status ;
r_log ( LOG_ICE , LOG_INFO , " ICE-PEER(%s)/CAND-PAIR(%s): setting pair to state %s: %s " ,
pctx - > label , pair - > codeword , nr_ice_cand_pair_states [ state ] , pair - > as_string ) ;
/* NOTE: This function used to reference pctx->state instead of
pair - > state and the assignment to pair - > state was at the top
of this function . Because pctx - > state was never changed , this seems to have
been a typo . The natural logic is " if the state changed
decrement the counter " so this implies we should be checking
the pair state rather than the pctx - > state .
This didn ' t cause big problems because waiting_pairs was only
used for pacing , so the pacing just was kind of broken .
This note is here as a reminder until we do more testing
and make sure that in fact this was a typo .
*/
if ( pair - > state ! = NR_ICE_PAIR_STATE_WAITING ) {
if ( state = = NR_ICE_PAIR_STATE_WAITING )
pctx - > waiting_pairs + + ;
}
else {
if ( state ! = NR_ICE_PAIR_STATE_WAITING )
pctx - > waiting_pairs - - ;
assert ( pctx - > waiting_pairs > = 0 ) ;
}
pair - > state = state ;
if ( pair - > state = = NR_ICE_PAIR_STATE_FAILED | |
pair - > state = = NR_ICE_PAIR_STATE_CANCELLED ) {
if ( r = nr_ice_component_failed_pair ( pair - > remote - > component , pair ) )
ABORT ( r ) ;
}
_status = 0 ;
abort :
return ( _status ) ;
}
int nr_ice_candidate_pair_dump_state ( nr_ice_cand_pair * pair , FILE * out )
{
/*r_log(LOG_ICE,LOG_DEBUG,"CAND-PAIR(%s): pair %s: state=%s, priority=0x%llx\n",pair->codeword,pair->as_string,nr_ice_cand_pair_states[pair->state],pair->priority);*/
return ( 0 ) ;
}
int nr_ice_candidate_pair_trigger_check_append ( nr_ice_cand_pair_head * head , nr_ice_cand_pair * pair )
{
if ( pair - > triggered_check_queue_entry . tqe_next | |
pair - > triggered_check_queue_entry . tqe_prev )
return ( 0 ) ;
TAILQ_INSERT_TAIL ( head , pair , triggered_check_queue_entry ) ;
return ( 0 ) ;
}
2020-06-17 03:18:17 +00:00
void nr_ice_candidate_pair_insert ( nr_ice_cand_pair_head * head , nr_ice_cand_pair * pair )
2017-04-19 07:56:45 +00:00
{
nr_ice_cand_pair * c1 ;
c1 = TAILQ_FIRST ( head ) ;
while ( c1 ) {
if ( c1 - > priority < pair - > priority ) {
TAILQ_INSERT_BEFORE ( c1 , pair , check_queue_entry ) ;
break ;
}
c1 = TAILQ_NEXT ( c1 , check_queue_entry ) ;
}
if ( ! c1 ) TAILQ_INSERT_TAIL ( head , pair , check_queue_entry ) ;
}
void nr_ice_candidate_pair_restart_stun_nominated_cb ( NR_SOCKET s , int how , void * cb_arg )
{
nr_ice_cand_pair * pair = cb_arg ;
int r , _status ;
pair - > restart_nominated_cb_timer = 0 ;
r_log ( LOG_ICE , LOG_INFO , " ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s)/COMP(%d): Restarting pair as nominated: %s " , pair - > pctx - > label , pair - > local - > stream - > label , pair - > codeword , pair - > remote - > component - > component_id , pair - > as_string ) ;
nr_stun_client_reset ( pair - > stun_client ) ;
if ( r = nr_stun_client_start ( pair - > stun_client , NR_ICE_CLIENT_MODE_USE_CANDIDATE , nr_ice_candidate_pair_stun_cb , pair ) )
ABORT ( r ) ;
if ( r = nr_ice_ctx_remember_id ( pair - > pctx - > ctx , pair - > stun_client - > request ) )
ABORT ( r ) ;
_status = 0 ;
abort :
return ;
}
static void nr_ice_candidate_pair_restart_stun_role_change_cb ( NR_SOCKET s , int how , void * cb_arg )
{
nr_ice_cand_pair * pair = cb_arg ;
pair - > restart_role_change_cb_timer = 0 ;
r_log ( LOG_ICE , LOG_INFO , " ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s):COMP(%d): Restarting pair as %s: %s " , pair - > pctx - > label , pair - > local - > stream - > label , pair - > codeword , pair - > remote - > component - > component_id , pair - > pctx - > controlling ? " CONTROLLING " : " CONTROLLED " , pair - > as_string ) ;
nr_ice_candidate_pair_restart ( pair - > pctx , pair ) ;
}
void nr_ice_candidate_pair_role_change ( nr_ice_cand_pair * pair )
{
pair - > stun_client - > params . ice_binding_request . control = pair - > pctx - > controlling ? NR_ICE_CONTROLLING : NR_ICE_CONTROLLED ;
if ( pair - > state = = NR_ICE_PAIR_STATE_IN_PROGRESS ) {
/* We could try only restarting in-progress pairs when they receive their
* 487 , but this ends up being simpler , because any extra 487 are dropped .
*/
if ( ! pair - > restart_role_change_cb_timer )
NR_ASYNC_TIMER_SET ( 0 , nr_ice_candidate_pair_restart_stun_role_change_cb , pair , & pair - > restart_role_change_cb_timer ) ;
}
}
static void nr_ice_candidate_pair_compute_codeword ( nr_ice_cand_pair * pair ,
nr_ice_candidate * lcand , nr_ice_candidate * rcand )
{
char as_string [ 2048 ] ;
snprintf ( as_string ,
sizeof ( as_string ) ,
" %s|%s(%s|%s) " ,
lcand - > addr . as_string ,
rcand - > addr . as_string ,
lcand - > label ,
rcand - > label ) ;
nr_ice_compute_codeword ( as_string , strlen ( as_string ) , pair - > codeword ) ;
}