summaryrefslogtreecommitdiff
path: root/res/res_http_websocket.c
diff options
context:
space:
mode:
authorAshley Sanders <asanders@digium.com>2015-07-31 11:27:23 -0500
committerAshley Sanders <asanders@digium.com>2015-07-31 11:28:10 -0500
commitfe804b09b31a1fd43de8d110f025c447aa4a6b62 (patch)
tree0971b1774f098df212816a66bdeed3bb48a5f4fc /res/res_http_websocket.c
parent309dd2a4090ccdd1ea31d8d5415a645daddd3883 (diff)
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
Diffstat (limited to 'res/res_http_websocket.c')
-rw-r--r--res/res_http_websocket.c44
1 files changed, 30 insertions, 14 deletions
diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c
index ecae03919..3fe774a0b 100644
--- a/res/res_http_websocket.c
+++ b/res/res_http_websocket.c
@@ -38,6 +38,7 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/file.h"
#include "asterisk/unaligned.h"
#include "asterisk/uri.h"
+#include "asterisk/uuid.h"
#define AST_API_MODULE
#include "asterisk/http_websocket.h"
@@ -74,18 +75,19 @@ ASTERISK_REGISTER_FILE()
/*! \brief Structure definition for session */
struct ast_websocket {
- FILE *f; /*!< Pointer to the file instance used for writing and reading */
- int fd; /*!< File descriptor for the session, only used for polling */
- struct ast_sockaddr address; /*!< Address of the remote client */
- enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */
- size_t payload_len; /*!< Length of the payload */
- char *payload; /*!< Pointer to the payload */
- size_t reconstruct; /*!< Number of bytes before a reconstructed payload will be returned and a new one started */
- int timeout; /*!< The timeout for operations on the socket */
- unsigned int secure:1; /*!< Bit to indicate that the transport is secure */
- unsigned int closing:1; /*!< Bit to indicate that the session is in the process of being closed */
- unsigned int close_sent:1; /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */
- struct websocket_client *client; /*!< Client object when connected as a client websocket */
+ FILE *f; /*!< Pointer to the file instance used for writing and reading */
+ int fd; /*!< File descriptor for the session, only used for polling */
+ struct ast_sockaddr address; /*!< Address of the remote client */
+ enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */
+ size_t payload_len; /*!< Length of the payload */
+ char *payload; /*!< Pointer to the payload */
+ size_t reconstruct; /*!< Number of bytes before a reconstructed payload will be returned and a new one started */
+ int timeout; /*!< The timeout for operations on the socket */
+ unsigned int secure:1; /*!< Bit to indicate that the transport is secure */
+ unsigned int closing:1; /*!< Bit to indicate that the session is in the process of being closed */
+ unsigned int close_sent:1; /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */
+ struct websocket_client *client; /*!< Client object when connected as a client websocket */
+ char session_id[AST_UUID_STR_LEN]; /*!< The identifier for the websocket session */
};
/*! \brief Hashing function for protocols */
@@ -414,6 +416,12 @@ int AST_OPTIONAL_API_NAME(ast_websocket_set_timeout)(struct ast_websocket *sessi
return 0;
}
+const char * AST_OPTIONAL_API_NAME(ast_websocket_session_id)(struct ast_websocket *session)
+{
+ return session->session_id;
+}
+
+
/* MAINTENANCE WARNING on ast_websocket_read()!
*
* We have to keep in mind during this function that the fact that session->fd seems ready
@@ -764,7 +772,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan
return 0;
}
- if (!(session = ao2_alloc(sizeof(*session), session_destroy_fn))) {
+ if (!(session = ao2_alloc(sizeof(*session) + AST_UUID_STR_LEN + 1, session_destroy_fn))) {
ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted\n",
ast_sockaddr_stringify(&ser->remote_address));
websocket_bad_request(ser);
@@ -773,8 +781,16 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan
}
session->timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
+ /* Generate the session id */
+ if (!ast_uuid_generate_str(session->session_id, sizeof(session->session_id))) {
+ ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - failed to generate a session id\n",
+ ast_sockaddr_stringify(&ser->remote_address));
+ ast_http_error(ser, 500, "Internal Server Error", "Allocation failed");
+ return 0;
+ }
+
if (protocol_handler->session_attempted
- && protocol_handler->session_attempted(ser, get_vars, headers)) {
+ && protocol_handler->session_attempted(ser, get_vars, headers, session->session_id)) {
ast_debug(3, "WebSocket connection from '%s' rejected by protocol handler '%s'\n",
ast_sockaddr_stringify(&ser->remote_address), protocol_handler->name);
ao2_ref(protocol_handler, -1);