[Asterisk-code-review] ARI: Ensure proper channel state on operations. (asterisk[master])

Mark Michelson asteriskteam at digium.com
Wed Jun 1 13:57:05 CDT 2016


Mark Michelson has uploaded a new change for review.

  https://gerrit.asterisk.org/2926

Change subject: ARI: Ensure proper channel state on operations.
......................................................................

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
---
M res/ari/resource_channels.c
M res/res_ari_channels.c
M res/res_ari_recordings.c
M rest-api/api-docs/channels.json
4 files changed, 177 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/26/2926/1

diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c
index 0f18b2d..bf60e97 100644
--- a/res/ari/resource_channels.c
+++ b/res/ari/resource_channels.c
@@ -54,6 +54,50 @@
 #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;
+	}
+
+	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.
  * \param[out] response Response to fill with an error if control is not found.
@@ -104,6 +148,10 @@
 
 	control = find_control(response, args->channel_id);
 	if (control == NULL) {
+		return;
+	}
+
+	if (channel_state_invalid(control, response)) {
 		return;
 	}
 
@@ -175,6 +223,10 @@
 		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 +281,10 @@
 		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 +306,10 @@
 		return;
 	}
 
+	if (channel_state_invalid(control, response)) {
+		return;
+	}
+
 	stasis_app_control_ring(control);
 
 	ast_ari_response_no_content(response);
@@ -263,6 +323,10 @@
 
 	control = find_control(response, args->channel_id);
 	if (control == NULL) {
+		return;
+	}
+
+	if (channel_state_invalid(control, response)) {
 		return;
 	}
 
@@ -358,6 +422,10 @@
 		return;
 	}
 
+	if (channel_state_invalid(control, response)) {
+		return;
+	}
+
 	if (ast_strlen_zero(args->dtmf)) {
 		ast_ari_response_error(
 			response, 400, "Bad Request",
@@ -382,6 +450,10 @@
 		return;
 	}
 
+	if (channel_state_invalid(control, response)) {
+		return;
+	}
+
 	stasis_app_control_hold(control);
 
 	ast_ari_response_no_content(response);
@@ -396,6 +468,10 @@
 	control = find_control(response, args->channel_id);
 	if (control == NULL) {
 		/* Response filled in by find_control */
+		return;
+	}
+
+	if (channel_state_invalid(control, response)) {
 		return;
 	}
 
@@ -416,6 +492,10 @@
 		return;
 	}
 
+	if (channel_state_invalid(control, response)) {
+		return;
+	}
+
 	stasis_app_control_moh_start(control, args->moh_class);
 	ast_ari_response_no_content(response);
 }
@@ -429,6 +509,10 @@
 	control = find_control(response, args->channel_id);
 	if (control == NULL) {
 		/* Response filled in by find_control */
+		return;
+	}
+
+	if (channel_state_invalid(control, response)) {
 		return;
 	}
 
@@ -448,6 +532,10 @@
 		return;
 	}
 
+	if (channel_state_invalid(control, response)) {
+		return;
+	}
+
 	stasis_app_control_silence_start(control);
 	ast_ari_response_no_content(response);
 }
@@ -461,6 +549,10 @@
 	control = find_control(response, args->channel_id);
 	if (control == NULL) {
 		/* Response filled in by find_control */
+		return;
+	}
+
+	if (channel_state_invalid(control, response)) {
 		return;
 	}
 
@@ -493,6 +585,10 @@
 		return;
 	}
 
+	if (channel_state_invalid(control, response)) {
+		return;
+	}
+
 	snapshot = stasis_app_control_get_snapshot(control);
 	if (!snapshot) {
 		ast_ari_response_error(
diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c
index 951a547..2b7bfe2 100644
--- a/res/res_ari_channels.c
+++ b/res/res_ari_channels.c
@@ -811,6 +811,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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:
diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c
index abc264d..a219435 100644
--- a/res/res_ari_recordings.c
+++ b/res/res_ari_recordings.c
@@ -257,6 +257,7 @@
 		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;
diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json
index aafd231..34436c7 100644
--- a/rest-api/api-docs/channels.json
+++ b/rest-api/api-docs/channels.json
@@ -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"
 						}
 					]
 				}

-- 
To view, visit https://gerrit.asterisk.org/2926
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I2ca51bf9ef2b44a1dc5a73f2d2de35c62c37dfd8
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Mark Michelson <mmichelson at digium.com>



More information about the asterisk-code-review mailing list