@ -2143,9 +2143,12 @@ int ast_hangup(struct ast_channel *chan)
ast_autoservice_stop ( chan ) ;
if ( chan - > masq ) {
if ( ast_do_masquerade ( chan ) )
ast_channel_unlock ( chan ) ;
if ( ast_do_masquerade ( chan ) ) {
ast_log ( LOG_WARNING , " Failed to perform masquerade \n " ) ;
}
ast_channel_lock ( chan ) ;
}
if ( chan - > masq ) {
ast_log ( LOG_WARNING , " %s getting hung up, but someone is trying to masq into us?!? \n " , chan - > name ) ;
@ -2514,13 +2517,13 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
/* Perform any pending masquerades */
for ( x = 0 ; x < n ; x + + ) {
ast_channel_lock ( c [ x ] ) ;
if ( c [ x ] - > masq & & ast_do_masquerade ( c [ x ] ) ) {
ast_log ( LOG_WARNING , " Masquerade failed \n " ) ;
* ms = - 1 ;
ast_channel_unlock ( c [ x ] ) ;
return NULL ;
}
ast_channel_lock ( c [ x ] ) ;
if ( ! ast_tvzero ( c [ x ] - > whentohangup ) ) {
if ( ast_tvzero ( whentohangup ) )
now = ast_tvnow ( ) ;
@ -2641,16 +2644,15 @@ static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan,
struct ast_channel * winner = NULL ;
struct ast_epoll_data * aed = NULL ;
ast_channel_lock ( chan ) ;
/* See if this channel needs to be masqueraded */
if ( chan - > masq & & ast_do_masquerade ( chan ) ) {
ast_log ( LOG_WARNING , " Failed to perform masquerade on %s \n " , chan - > name ) ;
* ms = - 1 ;
ast_channel_unlock ( chan ) ;
return NULL ;
}
ast_channel_lock ( chan ) ;
/* Figure out their timeout */
if ( ! ast_tvzero ( chan - > whentohangup ) ) {
if ( ( diff = ast_tvdiff_ms ( chan - > whentohangup , ast_tvnow ( ) ) ) < 0 ) {
@ -2726,13 +2728,13 @@ static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, i
struct ast_channel * winner = NULL ;
for ( i = 0 ; i < n ; i + + ) {
ast_channel_lock ( c [ i ] ) ;
if ( c [ i ] - > masq & & ast_do_masquerade ( c [ i ] ) ) {
ast_log ( LOG_WARNING , " Masquerade failed \n " ) ;
* ms = - 1 ;
ast_channel_unlock ( c [ i ] ) ;
return NULL ;
}
ast_channel_lock ( c [ i ] ) ;
if ( ! ast_tvzero ( c [ i ] - > whentohangup ) ) {
if ( whentohangup = = 0 )
now = ast_tvnow ( ) ;
@ -3064,26 +3066,23 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
struct ast_frame * f = NULL ; /* the return value */
int blah ;
int prestate ;
int c ount = 0 , c ause = 0 ;
int c ause = 0 ;
/* this function is very long so make sure there is only one return
* point at the end ( there are only two exceptions to this ) .
*/
while ( ast_channel_trylock ( chan ) ) {
if ( count + + > 10 )
/*cannot goto done since the channel is not locked*/
return & ast_null_frame ;
usleep ( 1 ) ;
}
if ( chan - > masq ) {
if ( ast_do_masquerade ( chan ) )
ast_log ( LOG_WARNING , " Failed to perform masquerade \n " ) ;
else
f = & ast_null_frame ;
goto done ;
return f ;
}
/* if here, no masq has happened, lock the channel and proceed */
ast_channel_lock ( chan ) ;
/* Stop if we're a zombie or need a soft hangup */
if ( ast_test_flag ( chan , AST_FLAG_ZOMBIE ) | | ast_check_hangup ( chan ) ) {
if ( chan - > generator )
@ -3893,9 +3892,13 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
goto done ;
/* Handle any pending masquerades */
if ( chan - > masq & & ast_do_masquerade ( chan ) ) {
if ( chan - > masq ) {
ast_channel_unlock ( chan ) ;
if ( ast_do_masquerade ( chan ) ) {
ast_log ( LOG_WARNING , " Failed to perform masquerade \n " ) ;
goto done ;
return res ; /* no need to goto done: chan is already unlocked for masq */
}
ast_channel_lock ( chan ) ;
}
if ( chan - > masqr ) {
res = 0 ; /* XXX explain, why 0 ? */
@ -4806,15 +4809,23 @@ retrymasq:
return res ;
}
void ast_change_name ( struct ast_channel * chan , const char * newname )
/*! \brief this function simply changes the name of the channel and issues a manager_event
* with out unlinking and linking the channel from the ao2_container . This should
* only be used when the channel has already been unlinked from the ao2_container .
*/
static void __ast_change_name_nolink ( struct ast_channel * chan , const char * newname )
{
/* We must re-link, as the hash value will change here. */
ao2_unlink ( channels , chan ) ;
manager_event ( EVENT_FLAG_CALL , " Rename " , " Channel: %s \r \n Newname: %s \r \n Uniqueid: %s \r \n " , chan - > name , newname , chan - > uniqueid ) ;
ast_string_field_set ( chan , name , newname ) ;
}
void ast_change_name ( struct ast_channel * chan , const char * newname )
{
/* We must re-link, as the hash value will change here. */
ao2_unlink ( channels , chan ) ;
ast_channel_lock ( chan ) ;
__ast_change_name_nolink ( chan , newname ) ;
ast_channel_unlock ( chan ) ;
ao2_link ( channels , chan ) ;
}
@ -5063,7 +5074,9 @@ static void report_new_callerid(const struct ast_channel *chan)
/*!
\ brief Masquerade a channel
\ note Assumes channel will be locked when called
\ note Assumes _NO_ channels and _NO_ channel pvt ' s are locked . If a channel is locked while calling
this function , it invalidates our channel container locking order . All channels
must be unlocked before it is permissible to lock the channels ' ao2 container .
*/
int ast_do_masquerade ( struct ast_channel * original )
{
@ -5078,7 +5091,7 @@ int ast_do_masquerade(struct ast_channel *original)
struct ast_party_connected_line connected ;
struct ast_party_redirecting redirecting ;
} exchange ;
struct ast_channel * clonechan = original - > masq ;
struct ast_channel * clonechan ;
struct ast_cdr * cdr ;
int rformat = original - > readformat ;
int wformat = original - > writeformat ;
@ -5092,8 +5105,52 @@ int ast_do_masquerade(struct ast_channel *original)
* original channel ' s backend . While the features are nice , which is the
* reason we ' re keeping it , it ' s still awesomely weird . XXX */
/* We need the clone's lock, too */
ast_channel_lock ( clonechan ) ;
/* The reasoning for the channels ao2_container lock here is complex.
*
* In order to check for a race condition , the original channel must
* be locked . If it is determined that the masquerade should proceed
* the original channel can absolutely not be unlocked until the end
* of the function . Since after determining the masquerade should
* continue requires the channels to be unlinked from the ao2_container ,
* the container lock must be held first to achieve proper locking order .
*/
ao2_lock ( channels ) ;
/* lock the original channel to determine if the masquerade is require or not */
ast_channel_lock ( original ) ;
/* This checks to see if the masquerade has already happened or not. There is a
* race condition that exists for this function . Since all pvt and channel locks
* must be let go before calling do_masquerade , it is possible that it could be
* called multiple times for the same channel . This check verifies whether
* or not the masquerade has already been completed by another thread */
if ( ! original - > masq ) {
ast_channel_unlock ( original ) ;
ao2_unlock ( channels ) ;
return 0 ; /* masq already completed by another thread, or never needed to be done to begin with */
}
/* now that we have verified no race condition exists, set the clone channel */
clonechan = original - > masq ;
/* since this function already holds the global container lock, unlocking original
* for deadlock avoidance will not result in any sort of masquerade race condition .
* If masq is called by a different thread while this happens , it will be stuck waiting
* until we unlock the container . */
while ( ast_channel_trylock ( clonechan ) ) {
CHANNEL_DEADLOCK_AVOIDANCE ( original ) ;
}
/* clear the masquerade channels */
original - > masq = NULL ;
clonechan - > masqr = NULL ;
/* unlink from channels container as name (which is the hash value) will change */
ao2_unlink ( channels , original ) ;
ao2_unlink ( channels , clonechan ) ;
/* now that both channels are locked and unlinked from the container, it is safe to unlock it */
ao2_unlock ( channels ) ;
ast_debug ( 4 , " Actually Masquerading %s(%d) into the structure of %s(%d) \n " ,
clonechan - > name , clonechan - > _state , original - > name , original - > _state ) ;
@ -5106,10 +5163,6 @@ int ast_do_masquerade(struct ast_channel *original)
free_translation ( clonechan ) ;
free_translation ( original ) ;
/* Unlink the masquerade */
original - > masq = NULL ;
clonechan - > masqr = NULL ;
/* Save the original name */
ast_copy_string ( orig , original - > name , sizeof ( orig ) ) ;
/* Save the new name */
@ -5118,10 +5171,10 @@ int ast_do_masquerade(struct ast_channel *original)
snprintf ( masqn , sizeof ( masqn ) , " %s<MASQ> " , newn ) ;
/* Mangle the name of the clone channel */
ast_change_name( clonechan , masqn ) ;
__ ast_change_name_nolink ( clonechan , masqn ) ;
/* Copy the name from the clone channel */
ast_change_name( original , newn ) ;
__ ast_change_name_nolink ( original , newn ) ;
/* share linked id's */
ast_channel_set_linkgroup ( original , clonechan ) ;
@ -5195,24 +5248,20 @@ int ast_do_masquerade(struct ast_channel *original)
original - > _state = clonechan - > _state ;
clonechan - > _state = origstate ;
if ( clonechan - > tech - > fixup ) {
res = clonechan - > tech - > fixup ( original , clonechan ) ;
if ( res )
if ( clonechan - > tech - > fixup & & clonechan - > tech - > fixup ( original , clonechan ) ) {
ast_log ( LOG_WARNING , " Fixup failed on channel %s, strange things may happen. \n " , clonechan - > name ) ;
}
/* Start by disconnecting the original's physical side */
if ( clonechan - > tech - > hangup )
res = clonechan - > tech - > hangup ( clonechan ) ;
if ( res ) {
if ( clonechan - > tech - > hangup & & clonechan - > tech - > hangup ( clonechan ) ) {
ast_log ( LOG_WARNING , " Hangup failed! Strange things may happen! \n " ) ;
ast_channel_unlock ( clonechan ) ;
return - 1 ;
res = - 1 ;
goto done ;
}
/* Mangle the name of the clone channel */
snprintf ( zombn , sizeof ( zombn ) , " %s<ZOMBIE> " , orig ) ;
ast_change_name( clonechan , zombn ) ;
snprintf ( zombn , sizeof ( zombn ) , " %s<ZOMBIE> " , orig ) ; /* quick, hide the brains! */
__ ast_change_name_nolink ( clonechan , zombn ) ;
/* Update the type. */
t_pvt = original - > monitor ;
@ -5306,12 +5355,11 @@ int ast_do_masquerade(struct ast_channel *original)
/* Okay. Last thing is to let the channel driver know about all this mess, so he
can fix up everything as best as possible */
if ( original - > tech - > fixup ) {
res = original - > tech - > fixup ( clonechan , original ) ;
if ( res ) {
if ( original - > tech - > fixup ( clonechan , original ) ) {
ast_log ( LOG_WARNING , " Channel for type '%s' could not fixup channel %s \n " ,
original - > tech - > type , original - > name ) ;
ast_channel_unlock ( clonechan ) ;
return - 1 ;
res = - 1 ;
goto done ;
}
} else
ast_log ( LOG_WARNING , " Channel type '%s' does not have a fixup routine (for %s)! Bad things may happen. \n " ,
@ -5350,13 +5398,24 @@ int ast_do_masquerade(struct ast_channel *original)
ast_debug ( 1 , " Released clone lock on '%s' \n " , clonechan - > name ) ;
ast_set_flag ( clonechan , AST_FLAG_ZOMBIE ) ;
ast_queue_frame ( clonechan , & ast_null_frame ) ;
ast_channel_unlock ( clonechan ) ;
}
/* Signal any blocker */
if ( ast_test_flag ( original , AST_FLAG_BLOCKING ) )
pthread_kill ( original - > blocker , SIGURG ) ;
ast_debug ( 1 , " Done Masquerading %s (%d) \n " , original - > name , original - > _state ) ;
done :
/* it is possible for the clone channel to disappear during this */
if ( clonechan ) {
ast_channel_unlock ( original ) ;
ast_channel_unlock ( clonechan ) ;
ao2_link ( channels , clonechan ) ;
ao2_link ( channels , original ) ;
} else {
ast_channel_unlock ( original ) ;
ao2_link ( channels , original ) ;
}
return 0 ;
}