@ -53,6 +53,60 @@ ASTERISK_REGISTER_FILE()
# include <limits.h>
/*!
* \ brief Ensure channel is in a state that allows operation to be performed .
*
* Since Asterisk 14 , it has been possible for down channels , as well as unanswered
* outbound channels to enter Stasis . While some operations are fine to perform on
* such channels , operations that
*
* - Attempt to manipulate channel state
* - Attempt to play media
* - Attempt to control the channel ' s location in the dialplan
*
* are invalid . This function can be used to determine if the channel is in an
* appropriate state .
*
* \ note When this function returns an error , the HTTP response is taken care of .
*
* \ param control The app control
* \ param response Response to fill in if there is an error
*
* \ retval 0 Channel is in a valid state . Continue on !
* \ retval non - zero Channel is in an invalid state . Bail !
*/
static int channel_state_invalid ( struct stasis_app_control * control ,
struct ast_ari_response * response )
{
struct ast_channel_snapshot * snapshot ;
snapshot = stasis_app_control_get_snapshot ( control ) ;
if ( ! snapshot ) {
ast_ari_response_error ( response , 404 , " Not Found " , " Channel not found " ) ;
return - 1 ;
}
/* These channel states apply only to outbound channels:
* - Down : Channel has been created , and nothing else has been done
* - Reserved : For a PRI , an underlying B - channel is reserved ,
* but the channel is not yet dialed
* - Ringing : The channel has been dialed .
*
* This does not affect inbound channels . Inbound channels , when they
* enter the dialplan , are in the " Ring " state . If they have already
* been answered , then they are in the " Up " state .
*/
if ( snapshot - > state = = AST_STATE_DOWN
| | snapshot - > state = = AST_STATE_RESERVED
| | snapshot - > state = = AST_STATE_RINGING ) {
ast_ari_response_error ( response , 412 , " Precondition Failed " ,
" Channel in invalid state " ) ;
return - 1 ;
}
return 0 ;
}
/*!
* \ brief Finds the control object for a channel , filling the response with an
* error , if appropriate .
@ -107,8 +161,13 @@ void ast_ari_channels_continue_in_dialplan(
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
snapshot = stasis_app_control_get_snapshot ( control ) ;
if ( ! snapshot ) {
ast_ari_response_error ( response , 404 , " Not Found " , " Channel not found " ) ;
return ;
}
@ -175,6 +234,10 @@ void ast_ari_channels_redirect(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
if ( ast_strlen_zero ( args - > endpoint ) ) {
ast_ari_response_error ( response , 400 , " Not Found " ,
" Required parameter 'endpoint' not provided. " ) ;
@ -229,6 +292,10 @@ void ast_ari_channels_answer(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
if ( stasis_app_control_answer ( control ) ! = 0 ) {
ast_ari_response_error (
response , 500 , " Internal Server Error " ,
@ -250,6 +317,10 @@ void ast_ari_channels_ring(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
stasis_app_control_ring ( control ) ;
ast_ari_response_no_content ( response ) ;
@ -266,6 +337,10 @@ void ast_ari_channels_ring_stop(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
stasis_app_control_ring_stop ( control ) ;
ast_ari_response_no_content ( response ) ;
@ -284,6 +359,10 @@ void ast_ari_channels_mute(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
if ( ast_strlen_zero ( args - > direction ) ) {
ast_ari_response_error (
response , 400 , " Bad Request " ,
@ -322,6 +401,10 @@ void ast_ari_channels_unmute(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
if ( ast_strlen_zero ( args - > direction ) ) {
ast_ari_response_error (
response , 400 , " Bad Request " ,
@ -358,6 +441,10 @@ void ast_ari_channels_send_dtmf(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
if ( ast_strlen_zero ( args - > dtmf ) ) {
ast_ari_response_error (
response , 400 , " Bad Request " ,
@ -382,6 +469,10 @@ void ast_ari_channels_hold(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
stasis_app_control_hold ( control ) ;
ast_ari_response_no_content ( response ) ;
@ -399,6 +490,10 @@ void ast_ari_channels_unhold(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
stasis_app_control_unhold ( control ) ;
ast_ari_response_no_content ( response ) ;
@ -416,6 +511,10 @@ void ast_ari_channels_start_moh(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
stasis_app_control_moh_start ( control , args - > moh_class ) ;
ast_ari_response_no_content ( response ) ;
}
@ -432,6 +531,10 @@ void ast_ari_channels_stop_moh(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
stasis_app_control_moh_stop ( control ) ;
ast_ari_response_no_content ( response ) ;
}
@ -448,6 +551,10 @@ void ast_ari_channels_start_silence(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
stasis_app_control_silence_start ( control ) ;
ast_ari_response_no_content ( response ) ;
}
@ -464,6 +571,10 @@ void ast_ari_channels_stop_silence(struct ast_variable *headers,
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
stasis_app_control_silence_stop ( control ) ;
ast_ari_response_no_content ( response ) ;
}
@ -493,6 +604,10 @@ static void ari_channels_handle_play(
return ;
}
if ( channel_state_invalid ( control , response ) ) {
return ;
}
snapshot = stasis_app_control_get_snapshot ( control ) ;
if ( ! snapshot ) {
ast_ari_response_error (