ARI: Channels added to Stasis application during WebSocket creation ...

Prior to ASTERISK-24988, the WebSocket handshake was resolved before Stasis
applications were registered. This was done such that the WebSocket would be
ready when an application is registered. However, by creating the WebSocket
first, the client had the ability to make requests for the Stasis application
it thought had been created with the initial handshake request. The inevitable
conclusion of this scenario was the cart being put before the horse.

ASTERISK-24988 resolved half of the problem by ensuring that the applications
were created and registered with Stasis prior to completing the handshake
with the client. While this meant that Stasis was ready when the client
received the green-light from Asterisk, it also meant that the WebSocket was
not yet ready for Stasis to dispatch messages.

This patch introduces a message queuing mechanism for delaying messages from
Stasis applications while the WebSocket is being constructed. When the ARI
event processor receives the message from the WebSocket that it is being
created, the event processor instantiates an event session which contains a
message queue. It then tries to create and register the requested applications
with Stasis. Messages that are dispatched from Stasis between this point and
the point at which the event processor is notified the WebSocket is ready, are
stashed in the queue. Once the WebSocket has been built, the queue's messages
are dispatched in the order in which they were originally received and the
queue is concurrently cleared.

ASTERISK-25181 #close
Reported By: Matt Jordan

Change-Id: Iafef7b85a2e0bf78c114db4c87ffc3d16d671a17
This commit is contained in:
Ashley Sanders
2015-07-31 11:27:23 -05:00
parent 309dd2a409
commit fe804b09b3
11 changed files with 499 additions and 193 deletions

View File

@@ -187,6 +187,16 @@ struct ast_json *ast_ari_websocket_session_read(
int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session,
struct ast_json *message);
/*!
* \brief Get the Session ID for an ARI WebSocket.
*
* \param session Session to query.
* \return Session ID.
* \return \c NULL on error.
*/
const char *ast_ari_websocket_session_id(
const struct ast_ari_websocket_session *session);
/*!
* \brief The stock message to return when out of memory.
*

View File

@@ -1642,7 +1642,7 @@ void *__ao2_unlink(struct ao2_container *c, void *obj, int flags,
* The use of flags argument is the follow:
*
* OBJ_UNLINK unlinks the object found
* OBJ_NODATA on match, do return an object
* OBJ_NODATA on match, do not return an object
* Callbacks use OBJ_NODATA as a default
* functions such as find() do
* OBJ_MULTIPLE return multiple matches

View File

@@ -77,13 +77,14 @@ struct ast_websocket;
* \param ser The TCP/TLS session
* \param parameters Parameters extracted from the request URI
* \param headers Headers included in the request
* \param session_id The id of the current session.
*
* \retval 0 The session should be accepted
* \retval -1 The session should be rejected. Note that the caller must send an error
* response using \ref ast_http_error.
* \since 13.5.0
*/
typedef int (*ast_websocket_pre_callback)(struct ast_tcptls_session_instance *ser, struct ast_variable *parameters, struct ast_variable *headers);
typedef int (*ast_websocket_pre_callback)(struct ast_tcptls_session_instance *ser, struct ast_variable *parameters, struct ast_variable *headers, const char *session_id);
/*!
* \brief Callback for when a new connection for a sub-protocol is established
@@ -359,6 +360,13 @@ AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session),
*/
AST_OPTIONAL_API(int, ast_websocket_set_nonblock, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
/*!
* \brief Get the session ID for a WebSocket session.
*
* \retval session id
*/
AST_OPTIONAL_API(const char *, ast_websocket_session_id, (struct ast_websocket *session), { errno = ENOSYS; return NULL;});
/*!
* \brief Result code for a websocket client.
*/

View File

@@ -110,7 +110,7 @@
/*!
* \brief Deallocates this vector.
*
* If any code to free the elements of this vector need to be run, that should
* If any code to free the elements of this vector needs to be run, that should
* be done prior to this call.
*
* \param vec Vector to deallocate.