ARI: Ensure proper channel state on operations.
ARI was recently outfitted with operations to create and dial channels. This leads to the ability to try funny stuff. You could create a channel and then immediately try to play back media on it. You could create a channel, dial it, and while it is ringing attempt to make it continue in the dialplan. This commit attempts to fix this by adding a channel state check to operations that should not be able to operate on outbound channels that have not yet answered. If a channel is in an invalid state, we will send a 412 response. ASTERISK-26047 #close Reported by Mark Michelson Change-Id: I2ca51bf9ef2b44a1dc5a73f2d2de35c62c37dfd8
This commit is contained in:
parent
608e0267e8
commit
1fd3a7849e
|
@ -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(
|
||||
|
|
|
@ -811,6 +811,7 @@ static void ast_ari_channels_continue_in_dialplan_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -911,6 +912,7 @@ static void ast_ari_channels_redirect_cb(
|
|||
case 404: /* Channel or endpoint not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 422: /* Endpoint is not the same type as the channel */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -971,6 +973,7 @@ static void ast_ari_channels_answer_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1031,6 +1034,7 @@ static void ast_ari_channels_ring_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1091,6 +1095,7 @@ static void ast_ari_channels_ring_stop_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1218,6 +1223,7 @@ static void ast_ari_channels_send_dtmf_cb(
|
|||
case 400: /* DTMF is required */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1316,6 +1322,7 @@ static void ast_ari_channels_mute_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1414,6 +1421,7 @@ static void ast_ari_channels_unmute_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1474,6 +1482,7 @@ static void ast_ari_channels_hold_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1534,6 +1543,7 @@ static void ast_ari_channels_unhold_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1632,6 +1642,7 @@ static void ast_ari_channels_start_moh_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1692,6 +1703,7 @@ static void ast_ari_channels_stop_moh_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1752,6 +1764,7 @@ static void ast_ari_channels_start_silence_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -1812,6 +1825,7 @@ static void ast_ari_channels_stop_silence_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -2003,6 +2017,7 @@ static void ast_ari_channels_play_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -2192,6 +2207,7 @@ static void ast_ari_channels_play_with_id_cb(
|
|||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -257,6 +257,7 @@ static void ast_ari_recordings_get_stored_file_cb(
|
|||
break;
|
||||
case 500: /* Internal Server Error */
|
||||
case 501: /* Not Implemented */
|
||||
case 403: /* The recording file could not be opened */
|
||||
case 404: /* Recording not found */
|
||||
is_valid = 1;
|
||||
break;
|
||||
|
|
|
@ -453,6 +453,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -501,6 +505,10 @@
|
|||
{
|
||||
"code": 422,
|
||||
"reason": "Endpoint is not the same type as the channel"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -533,6 +541,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -565,6 +577,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -591,6 +607,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -671,6 +691,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -720,6 +744,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -763,6 +791,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -795,6 +827,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -821,6 +857,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -862,6 +902,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -888,6 +932,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -921,6 +969,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -947,6 +999,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1021,6 +1077,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1095,6 +1155,10 @@
|
|||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue