res_ari_events: Fix shutdown ref leak.
[asterisk/asterisk.git] / res / res_ari_events.c
index aea318d..4b2b151 100644 (file)
@@ -53,7 +53,93 @@ ASTERISK_REGISTER_FILE()
 
 #define MAX_VALS 128
 
-static void ast_ari_events_event_websocket_ws_cb(struct ast_websocket *ws_session,
+static int ast_ari_events_event_websocket_ws_attempted_cb(struct ast_tcptls_session_instance *ser,
+       struct ast_variable *get_params, struct ast_variable *headers, const char *session_id)
+{
+       struct ast_ari_events_event_websocket_args args = {};
+       int res = 0;
+       RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
+       struct ast_variable *i;
+
+       response = ast_calloc(1, sizeof(*response));
+       if (!response) {
+               ast_log(LOG_ERROR, "Failed to create response.\n");
+               goto fin;
+       }
+
+       for (i = get_params; i; i = i->next) {
+               if (strcmp(i->name, "app") == 0) {
+                       /* Parse comma separated list */
+                       char *vals[MAX_VALS];
+                       size_t j;
+
+                       args.app_parse = ast_strdup(i->value);
+                       if (!args.app_parse) {
+                               ast_ari_response_alloc_failed(response);
+                               goto fin;
+                       }
+
+                       if (strlen(args.app_parse) == 0) {
+                               /* ast_app_separate_args can't handle "" */
+                               args.app_count = 1;
+                               vals[0] = args.app_parse;
+                       } else {
+                               args.app_count = ast_app_separate_args(
+                                       args.app_parse, ',', vals,
+                                       ARRAY_LEN(vals));
+                       }
+
+                       if (args.app_count == 0) {
+                               ast_ari_response_alloc_failed(response);
+                               goto fin;
+                       }
+
+                       if (args.app_count >= MAX_VALS) {
+                               ast_ari_response_error(response, 400,
+                                       "Bad Request",
+                                       "Too many values for app");
+                               goto fin;
+                       }
+
+                       args.app = ast_malloc(sizeof(*args.app) * args.app_count);
+                       if (!args.app) {
+                               ast_ari_response_alloc_failed(response);
+                               goto fin;
+                       }
+
+                       for (j = 0; j < args.app_count; ++j) {
+                               args.app[j] = (vals[j]);
+                       }
+               } else
+               {}
+       }
+
+       res = ast_ari_websocket_events_event_websocket_attempted(ser, headers, &args, session_id);
+
+fin: __attribute__((unused))
+       if (!response) {
+               ast_http_error(ser, 500, "Server Error", "Memory allocation error");
+               res = -1;
+       } else if (response->response_code != 0) {
+               /* Param parsing failure */
+               RAII_VAR(char *, msg, NULL, ast_json_free);
+               if (response->message) {
+                       msg = ast_json_dump_string(response->message);
+               } else {
+                       ast_log(LOG_ERROR, "Missing response message\n");
+               }
+
+               if (msg) {
+                       ast_http_error(ser, response->response_code, response->response_text, msg);
+               }
+               res = -1;
+       }
+       ast_free(args.app_parse);
+       ast_free(args.app);
+       return res;
+}
+
+static void ast_ari_events_event_websocket_ws_established_cb(struct ast_websocket *ws_session,
        struct ast_variable *get_params, struct ast_variable *headers)
 {
        struct ast_ari_events_event_websocket_args args = {};
@@ -126,16 +212,11 @@ static void ast_ari_events_event_websocket_ws_cb(struct ast_websocket *ws_sessio
                {}
        }
 
-       ast_ari_websocket_events_event_websocket(session, headers, &args);
+       ast_ari_websocket_events_event_websocket_established(session, headers, &args);
 
 fin: __attribute__((unused))
        if (response && response->response_code != 0) {
                /* Param parsing failure */
-               /* TODO - ideally, this would return the error code to the
-                * HTTP client; but we've already done the WebSocket
-                * negotiation. Param parsing should happen earlier, but we
-                * need a way to pass it through the WebSocket code to the
-                * callback */
                RAII_VAR(char *, msg, NULL, ast_json_free);
                if (response->message) {
                        msg = ast_json_dump_string(response->message);
@@ -351,12 +432,26 @@ static struct stasis_rest_handlers events = {
 static int load_module(void)
 {
        int res = 0;
+       struct ast_websocket_protocol *protocol;
+
+       if (ast_ari_websocket_events_event_websocket_init() == -1) {
+               return AST_MODULE_LOAD_FAILURE;
+       }
+
        events.ws_server = ast_websocket_server_create();
        if (!events.ws_server) {
                return AST_MODULE_LOAD_FAILURE;
        }
-       res |= ast_websocket_server_add_protocol(events.ws_server,
-               "ari", ast_ari_events_event_websocket_ws_cb);
+
+       protocol = ast_websocket_sub_protocol_alloc("ari");
+       if (!protocol) {
+               ao2_ref(events.ws_server, -1);
+               events.ws_server = NULL;
+               return AST_MODULE_LOAD_FAILURE;
+       }
+       protocol->session_attempted = ast_ari_events_event_websocket_ws_attempted_cb;
+       protocol->session_established = ast_ari_events_event_websocket_ws_established_cb;
+       res |= ast_websocket_server_add_protocol2(events.ws_server, protocol);
        stasis_app_ref();
        res |= ast_ari_add_handler(&events);
        return res;
@@ -367,6 +462,7 @@ static int unload_module(void)
        ast_ari_remove_handler(&events);
        ao2_cleanup(events.ws_server);
        events.ws_server = NULL;
+       ast_ari_websocket_events_event_websocket_dtor();
        stasis_app_unref();
        return 0;
 }
@@ -376,4 +472,4 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Web
        .load = load_module,
        .unload = unload_module,
        .nonoptreq = "res_ari,res_stasis",
-       );
+);