diff options
Diffstat (limited to 'res/res_stasis_websocket.c')
-rw-r--r-- | res/res_stasis_websocket.c | 293 |
1 files changed, 0 insertions, 293 deletions
diff --git a/res/res_stasis_websocket.c b/res/res_stasis_websocket.c deleted file mode 100644 index 5d6dcb6a9..000000000 --- a/res/res_stasis_websocket.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2012 - 2013, Digium, Inc. - * - * David M. Lee, II <dlee@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief HTTP binding for the Stasis API - * - * \author David M. Lee, II <dlee@digium.com> - */ - -/*** MODULEINFO - <depend type="module">res_stasis</depend> - <depend type="module">res_http_websocket</depend> - <support_level>core</support_level> - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/astobj2.h" -#include "asterisk/http_websocket.h" -#include "asterisk/json.h" -#include "asterisk/module.h" -#include "asterisk/stasis_app.h" -#include "asterisk/strings.h" -#include "asterisk/utils.h" - -/*! WebSocket protocol for Stasis */ -static const char * const ws_protocol = "stasis"; - -/*! Message to send when out of memory */ -static struct ast_json *oom_json; - -/*! Number of buckets for the Stasis application hash table. Remember to keep it - * a prime number! - */ -#define APPS_NUM_BUCKETS 7 - -/*! - * \internal - * \brief Helper to write a JSON object to a WebSocket. - * \param session WebSocket session. - * \param message JSON message. - * \return 0 on success. - * \return -1 on error. - */ -static int websocket_write_json(struct ast_websocket *session, - struct ast_json *message) -{ - RAII_VAR(char *, str, ast_json_dump_string(message), ast_free); - - if (str == NULL) { - ast_log(LOG_ERROR, "Failed to encode JSON object\n"); - return -1; - } - - return ast_websocket_write(session, AST_WEBSOCKET_OPCODE_TEXT, str, - strlen(str)); -} - -struct stasis_ws_session_info { - struct ast_websocket *ws_session; - struct ao2_container *websocket_apps; -}; - -static void session_dtor(void *obj) -{ -#ifdef AST_DEVMODE /* Avoid unused variable warning */ - struct stasis_ws_session_info *session = obj; -#endif - - /* session_shutdown should have been called before */ - ast_assert(session->ws_session == NULL); - ast_assert(session->websocket_apps == NULL); -} - -static struct stasis_ws_session_info *session_create( - struct ast_websocket *ws_session) -{ - RAII_VAR(struct stasis_ws_session_info *, session, NULL, ao2_cleanup); - - session = ao2_alloc(sizeof(*session), session_dtor); - - session->ws_session = ws_session; - session->websocket_apps = - ast_str_container_alloc(APPS_NUM_BUCKETS); - - if (!session->websocket_apps) { - return NULL; - } - - ao2_ref(session, +1); - return session; -} - -/*! - * \brief Explicitly shutdown a session. - * - * An explicit shutdown is necessary, since stasis-app has a reference to this - * session. We also need to be sure to null out the \c ws_session field, since - * the websocket is about to go away. - * - * \param session Session info struct. - */ -static void session_shutdown(struct stasis_ws_session_info *session) -{ - struct ao2_iterator i; - char *app; - SCOPED_AO2LOCK(lock, session); - - i = ao2_iterator_init(session->websocket_apps, 0); - while ((app = ao2_iterator_next(&i))) { - stasis_app_unregister(app); - ao2_cleanup(app); - } - ao2_iterator_destroy(&i); - ao2_cleanup(session->websocket_apps); - - session->websocket_apps = NULL; - session->ws_session = NULL; -} - -/*! - * \brief Callback handler for Stasis application messages. - */ -static void app_handler(void *data, const char *app_name, - struct ast_json *message) -{ - struct stasis_ws_session_info *session = data; - int res; - - res = ast_json_object_set(message, "application", - ast_json_string_create(app_name)); - if(res != 0) { - return; - } - - ao2_lock(session); - if (session->ws_session) { - websocket_write_json(session->ws_session, message); - } - ao2_unlock(session); -} - -/*! - * \brief Register for all of the apps given. - * \param session Session info struct. - * \param app_list Comma seperated list of app names to register. - */ -static int session_register_apps(struct stasis_ws_session_info *session, - const char *app_list) -{ - RAII_VAR(char *, to_free, NULL, ast_free); - char *apps, *app_name; - SCOPED_AO2LOCK(lock, session); - - ast_assert(session->ws_session != NULL); - ast_assert(session->websocket_apps != NULL); - - to_free = apps = ast_strdup(app_list); - if (!apps) { - websocket_write_json(session->ws_session, oom_json); - return -1; - } - while ((app_name = strsep(&apps, ","))) { - if (ast_str_container_add(session->websocket_apps, app_name)) { - websocket_write_json(session->ws_session, oom_json); - return -1; - } - - stasis_app_register(app_name, app_handler, session); - } - return 0; -} - -static void websocket_callback(struct ast_websocket *ws_session, - struct ast_variable *parameters, - struct ast_variable *headers) -{ - RAII_VAR(struct stasis_ws_session_info *, stasis_session, NULL, ao2_cleanup); - struct ast_variable *param = NULL; - int res; - - ast_debug(3, "Stasis web socket connection\n"); - - if (ast_websocket_set_nonblock(ws_session) != 0) { - ast_log(LOG_ERROR, - "Stasis web socket failed to set nonblock; closing\n"); - goto end; - } - - stasis_session = session_create(ws_session); - - if (!stasis_session) { - websocket_write_json(ws_session, oom_json); - goto end; - } - - for (param = parameters; param; param = param->next) { - if (strcmp(param->name, "app") == 0) { - int ret = session_register_apps( - stasis_session, param->value); - if (ret != 0) { - goto end; - } - } - } - - if (ao2_container_count(stasis_session->websocket_apps) == 0) { - RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref); - - msg = ast_json_pack("{s: s, s: [s]}", - "error", "MissingParams", - "params", "app"); - if (msg) { - websocket_write_json(ws_session, msg); - } - - goto end; - } - - while ((res = ast_wait_for_input(ast_websocket_fd(ws_session), -1)) > 0) { - char *payload; - uint64_t payload_len; - enum ast_websocket_opcode opcode; - int fragmented; - int read = ast_websocket_read(ws_session, &payload, &payload_len, - &opcode, &fragmented); - - if (read) { - ast_log(LOG_ERROR, - "Stasis WebSocket read error; closing\n"); - break; - } - - if (opcode == AST_WEBSOCKET_OPCODE_CLOSE) { - break; - } - } - -end: - session_shutdown(stasis_session); - ast_websocket_unref(ws_session); -} - -static int load_module(void) -{ - int r = 0; - - stasis_app_ref(); - oom_json = ast_json_pack("{s: s}", - "error", "OutOfMemory"); - if (!oom_json) { - /* ironic */ - return AST_MODULE_LOAD_FAILURE; - } - r |= ast_websocket_add_protocol(ws_protocol, websocket_callback); - return r; -} - -static int unload_module(void) -{ - int r = 0; - - stasis_app_unref(); - ast_json_unref(oom_json); - oom_json = NULL; - r |= ast_websocket_remove_protocol(ws_protocol, websocket_callback); - return r; -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Stasis HTTP bindings", - .load = load_module, - .unload = unload_module, - .nonoptreq = "res_stasis,res_http_websocket", - .load_pri = AST_MODPRI_APP_DEPEND, - ); |