]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
ARI: Ensure proper channel state on operations. 26/2926/3
authorMark Michelson <mmichelson@digium.com>
Wed, 1 Jun 2016 18:48:00 +0000 (13:48 -0500)
committerMark Michelson <mmichelson@digium.com>
Thu, 9 Jun 2016 19:43:15 +0000 (14:43 -0500)
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

res/ari/resource_channels.c
res/res_ari_channels.c
res/res_ari_recordings.c
rest-api/api-docs/channels.json

index 0f18b2dc1d5117e18d2425b5547ed2f63419a8db..88e66f11ab9e7ed9497ddf9dad014f55e6d3b89e 100644 (file)
@@ -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(
index 951a5475bc030ec776d9b47557c55f5fb32d9f22..2b7bfe2dbcf797fc0b54313d2f828177ebd0281b 100644 (file)
@@ -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:
index abc264d9e51ea201a97a1cad326faaaa87ec8548..a21943520c9134c3eb05904b8abd975476b1874a 100644 (file)
@@ -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;
index aafd231a1f31a09a0eca8dbe53e2835707fcb9e4..34436c7b8c0f7bb40f2fc641d46cb1ea043b00fe 100644 (file)
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 422,
                                                        "reason": "Endpoint is not the same type as the channel"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                },
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                },
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                },
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                },
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                },
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }
                                                {
                                                        "code": 409,
                                                        "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
                                                }
                                        ]
                                }