[asterisk-commits] dlee: trunk r386020 - in /trunk: include/asterisk/ res/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Apr 18 12:30:35 CDT 2013


Author: dlee
Date: Thu Apr 18 12:30:28 2013
New Revision: 386020

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386020
Log:
Allow WebSocket connections on more URL's

This patch adds the concept of ast_websocket_server to
res_http_websocket, allowing WebSocket connections on URL's more more
than /ws.

The existing funcitons for managing the WebSocket subprotocols on /ws
still work, so this patch should be completely backward compatible.

(closes issue ASTERISK-21279)
Review: https://reviewboard.asterisk.org/r/2453/

Modified:
    trunk/include/asterisk/http_websocket.h
    trunk/res/res_http_websocket.c

Modified: trunk/include/asterisk/http_websocket.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/http_websocket.h?view=diff&rev=386020&r1=386019&r2=386020
==============================================================================
--- trunk/include/asterisk/http_websocket.h (original)
+++ trunk/include/asterisk/http_websocket.h Thu Apr 18 12:30:28 2013
@@ -19,6 +19,7 @@
 #ifndef _ASTERISK_HTTP_WEBSOCKET_H
 #define _ASTERISK_HTTP_WEBSOCKET_H
 
+#include "asterisk/http.h"
 #include "asterisk/optional_api.h"
 
 /*!
@@ -40,7 +41,13 @@
 };
 
 /*!
- * \brief Opaque structure for WebSocket sessions
+ * \brief Opaque structure for WebSocket server.
+ * \since 12
+ */
+struct ast_websocket_server;
+
+/*!
+ * \brief Opaque structure for WebSocket sessions.
  */
 struct ast_websocket;
 
@@ -58,7 +65,24 @@
 typedef void (*ast_websocket_callback)(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers);
 
 /*!
- * \brief Add a sub-protocol handler to the server
+ * \brief Creates a \ref websocket_server
+ *
+ * \retval New \ref websocket_server instance
+ * \retval \c NULL on error
+ * \since 12
+ */
+struct ast_websocket_server *ast_websocket_server_create(void);
+
+/*!
+ * \brief Callback suitable for use with a \ref ast_http_uri.
+ *
+ * Set the data field of the ast_http_uri to \ref ast_websocket_server.
+ * \since 12
+ */
+int ast_websocket_uri_cb(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers);
+
+/*!
+ * \brief Add a sub-protocol handler to the default /ws server
  *
  * \param name Name of the sub-protocol to register
  * \param callback Callback called when a new connection requesting the sub-protocol is established
@@ -69,7 +93,7 @@
 AST_OPTIONAL_API(int, ast_websocket_add_protocol, (const char *name, ast_websocket_callback callback), {return -1;});
 
 /*!
- * \brief Remove a sub-protocol handler from the server
+ * \brief Remove a sub-protocol handler from the default /ws server.
  *
  * \param name Name of the sub-protocol to unregister
  * \param callback Callback that was previously registered with the sub-protocol
@@ -78,6 +102,30 @@
  * \retval -1 if sub-protocol was not found or if callback did not match
  */
 AST_OPTIONAL_API(int, ast_websocket_remove_protocol, (const char *name, ast_websocket_callback callback), {return -1;});
+
+/*!
+ * \brief Add a sub-protocol handler to the given server.
+ *
+ * \param name Name of the sub-protocol to register
+ * \param callback Callback called when a new connection requesting the sub-protocol is established
+ *
+ * \retval 0 success
+ * \retval -1 if sub-protocol handler could not be registered
+ * \since 12
+ */
+AST_OPTIONAL_API(int, ast_websocket_server_add_protocol, (struct ast_websocket_server *server, const char *name, ast_websocket_callback callback), {return -1;});
+
+/*!
+ * \brief Remove a sub-protocol handler from the given server.
+ *
+ * \param name Name of the sub-protocol to unregister
+ * \param callback Callback that was previously registered with the sub-protocol
+ *
+ * \retval 0 success
+ * \retval -1 if sub-protocol was not found or if callback did not match
+ * \since 12
+ */
+AST_OPTIONAL_API(int, ast_websocket_server_remove_protocol, (struct ast_websocket_server *server, const char *name, ast_websocket_callback callback), {return -1;});
 
 /*!
  * \brief Read a WebSocket frame and handle it

Modified: trunk/res/res_http_websocket.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_http_websocket.c?view=diff&rev=386020&r1=386019&r2=386020
==============================================================================
--- trunk/res/res_http_websocket.c (original)
+++ trunk/res/res_http_websocket.c Thu Apr 18 12:30:28 2013
@@ -77,9 +77,6 @@
 	ast_websocket_callback callback; /*!< Callback called when a new session is established */
 };
 
-/*! \brief Container for registered protocols */
-static struct ao2_container *protocols;
-
 /*! \brief Hashing function for protocols */
 static int protocol_hash_fn(const void *obj, const int flags)
 {
@@ -103,6 +100,36 @@
 {
 	struct websocket_protocol *protocol = obj;
 	ast_free(protocol->name);
+}
+
+/*! \brief Structure for a WebSocket server */
+struct ast_websocket_server {
+	struct ao2_container *protocols; /*!< Container for registered protocols */
+};
+
+static void websocket_server_dtor(void *obj)
+{
+	struct ast_websocket_server *server = obj;
+	ao2_cleanup(server->protocols);
+	server->protocols = NULL;
+}
+
+struct ast_websocket_server *ast_websocket_server_create(void)
+{
+	RAII_VAR(struct ast_websocket_server *, server, NULL, ao2_cleanup);
+
+	server = ao2_alloc(sizeof(*server), websocket_server_dtor);
+	if (!server) {
+		return NULL;
+	}
+
+	server->protocols = ao2_container_alloc(MAX_PROTOCOL_BUCKETS, protocol_hash_fn, protocol_cmp_fn);
+	if (!server->protocols) {
+		return NULL;
+	}
+
+	ao2_ref(server, +1);
+	return server;
 }
 
 /*! \brief Destructor function for sessions */
@@ -118,38 +145,38 @@
 	ast_free(session->payload);
 }
 
-int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol)(const char *name, ast_websocket_callback callback)
+int AST_OPTIONAL_API_NAME(ast_websocket_server_add_protocol)(struct ast_websocket_server *server, const char *name, ast_websocket_callback callback)
 {
 	struct websocket_protocol *protocol;
 
-	if (!protocols) {
-		return -1;
-	}
-
-	ao2_lock(protocols);
+	if (!server->protocols) {
+		return -1;
+	}
+
+	ao2_lock(server->protocols);
 
 	/* Ensure a second protocol handler is not registered for the same protocol */
-	if ((protocol = ao2_find(protocols, name, OBJ_KEY | OBJ_NOLOCK))) {
+	if ((protocol = ao2_find(server->protocols, name, OBJ_KEY | OBJ_NOLOCK))) {
 		ao2_ref(protocol, -1);
-		ao2_unlock(protocols);
+		ao2_unlock(server->protocols);
 		return -1;
 	}
 
 	if (!(protocol = ao2_alloc(sizeof(*protocol), protocol_destroy_fn))) {
-		ao2_unlock(protocols);
+		ao2_unlock(server->protocols);
 		return -1;
 	}
 
 	if (!(protocol->name = ast_strdup(name))) {
 		ao2_ref(protocol, -1);
-		ao2_unlock(protocols);
+		ao2_unlock(server->protocols);
 		return -1;
 	}
 
 	protocol->callback = callback;
 
-	ao2_link_flags(protocols, protocol, OBJ_NOLOCK);
-	ao2_unlock(protocols);
+	ao2_link_flags(server->protocols, protocol, OBJ_NOLOCK);
+	ao2_unlock(server->protocols);
 	ao2_ref(protocol, -1);
 
 	ast_verb(2, "WebSocket registered sub-protocol '%s'\n", name);
@@ -157,15 +184,11 @@
 	return 0;
 }
 
-int AST_OPTIONAL_API_NAME(ast_websocket_remove_protocol)(const char *name, ast_websocket_callback callback)
+int AST_OPTIONAL_API_NAME(ast_websocket_server_remove_protocol)(struct ast_websocket_server *server, const char *name, ast_websocket_callback callback)
 {
 	struct websocket_protocol *protocol;
 
-	if (!protocols) {
-		return -1;
-	}
-
-	if (!(protocol = ao2_find(protocols, name, OBJ_KEY))) {
+	if (!(protocol = ao2_find(server->protocols, name, OBJ_KEY))) {
 		return -1;
 	}
 
@@ -174,7 +197,7 @@
 		return -1;
 	}
 
-	ao2_unlink(protocols, protocol);
+	ao2_unlink(server->protocols, protocol);
 	ao2_ref(protocol, -1);
 
 	ast_verb(2, "WebSocket unregistered sub-protocol '%s'\n", name);
@@ -474,20 +497,22 @@
 	return 0;
 }
 
-/*! \brief Callback that is executed everytime an HTTP request is received by this module */
-static int websocket_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
+int ast_websocket_uri_cb(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
 {
 	struct ast_variable *v;
 	char *upgrade = NULL, *key = NULL, *key1 = NULL, *key2 = NULL, *protos = NULL, *requested_protocols = NULL, *protocol = NULL;
 	int version = 0, flags = 1;
 	struct websocket_protocol *protocol_handler = NULL;
 	struct ast_websocket *session;
+	struct ast_websocket_server *server;
 
 	/* Upgrade requests are only permitted on GET methods */
 	if (method != AST_HTTP_GET) {
 		ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
 		return -1;
 	}
+
+	server = urih->data;
 
 	/* Get the minimum headers required to satisfy our needs */
 	for (v = headers; v; v = v->next) {
@@ -533,7 +558,7 @@
 
 	/* Iterate through the requested protocols trying to find one that we have a handler for */
 	while ((protocol = strsep(&requested_protocols, ","))) {
-		if ((protocol_handler = ao2_find(protocols, ast_strip(protocol), OBJ_KEY))) {
+		if ((protocol_handler = ao2_find(server->protocols, ast_strip(protocol), OBJ_KEY))) {
 			break;
 		}
 	}
@@ -619,7 +644,7 @@
 }
 
 static struct ast_http_uri websocketuri = {
-	.callback = websocket_callback,
+	.callback = ast_websocket_uri_cb,
 	.description = "Asterisk HTTP WebSocket",
 	.uri = "ws",
 	.has_subtree = 0,
@@ -664,9 +689,30 @@
 	ast_websocket_unref(session);
 }
 
+int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol)(const char *name, ast_websocket_callback callback)
+{
+	struct ast_websocket_server *ws_server = websocketuri.data;
+	if (!ws_server) {
+		return -1;
+	}
+	return ast_websocket_server_add_protocol(ws_server, name, callback);
+}
+
+int AST_OPTIONAL_API_NAME(ast_websocket_remove_protocol)(const char *name, ast_websocket_callback callback)
+{
+	struct ast_websocket_server *ws_server = websocketuri.data;
+	if (!ws_server) {
+		return -1;
+	}
+	return ast_websocket_server_remove_protocol(ws_server, name, callback);
+}
+
 static int load_module(void)
 {
-	protocols = ao2_container_alloc(MAX_PROTOCOL_BUCKETS, protocol_hash_fn, protocol_cmp_fn);
+	websocketuri.data = ast_websocket_server_create();
+	if (!websocketuri.data) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
 	ast_http_uri_link(&websocketuri);
 	ast_websocket_add_protocol("echo", websocket_echo_callback);
 
@@ -677,8 +723,8 @@
 {
 	ast_websocket_remove_protocol("echo", websocket_echo_callback);
 	ast_http_uri_unlink(&websocketuri);
-	ao2_ref(protocols, -1);
-	protocols = NULL;
+	ao2_ref(websocketuri.data, -1);
+	websocketuri.data = NULL;
 
 	return 0;
 }




More information about the asterisk-commits mailing list