]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_stasis: Fix crash on a hanging up channel. 15/2515/1
authorRichard Mudgett <rmudgett@digium.com>
Mon, 28 Mar 2016 23:10:40 +0000 (18:10 -0500)
committerRichard Mudgett <rmudgett@digium.com>
Wed, 30 Mar 2016 21:48:47 +0000 (16:48 -0500)
* Give the struct stasis_app_control ao2 object a ref to the channel held
in the object.  Now the channel will still be around if a thread needs to
post a stasis message instead of crash because the topic was destroyed.

* Moved stopping any lingering silence generator out of the struct
stasis_app_control destructor and made it a part of exiting the Stasis
application.  Who knows which thread the destructor will be called under
so it cannot affect the channel's silence generator.  Not only was the
channel unprotected when the silence generator was stopped, stasis may no
longer even control the channel.

ASTERISK-25882

Change-Id: I21728161b5fe638cef7976fa36a605043a7497e4

res/res_stasis.c
res/stasis/control.c
res/stasis/control.h

index 180dd2355cdb18f6ff65b223f9e2d0c7b9986901..3f03f58167565672acb7279071ad830868936b89 100644 (file)
@@ -1364,6 +1364,9 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
                remove_stasis_end_published(chan);
        }
 
+       /* Stop any lingering silence generator */
+       control_silence_stop_now(control);
+
        /* There's an off chance that app is ready for cleanup. Go ahead
         * and clean up, just in case
         */
index 0d5a5f14e49e78a651b2473119f5b413984c66f5..97390612ac813bc3dc533b6120e523d89ec28974 100644 (file)
@@ -87,21 +87,19 @@ static void control_dtor(void *obj)
 {
        struct stasis_app_control *control = obj;
 
-       AST_LIST_HEAD_DESTROY(&control->add_rules);
-       AST_LIST_HEAD_DESTROY(&control->remove_rules);
+       ao2_cleanup(control->command_queue);
 
-       /* We may have a lingering silence generator; free it */
-       ast_channel_stop_silence_generator(control->channel, control->silgen);
-       control->silgen = NULL;
+       ast_channel_cleanup(control->channel);
+       ao2_cleanup(control->app);
 
-       ao2_cleanup(control->command_queue);
        ast_cond_destroy(&control->wait_cond);
-       ao2_cleanup(control->app);
+       AST_LIST_HEAD_DESTROY(&control->add_rules);
+       AST_LIST_HEAD_DESTROY(&control->remove_rules);
 }
 
 struct stasis_app_control *control_create(struct ast_channel *channel, struct stasis_app *app)
 {
-       RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+       struct stasis_app_control *control;
        int res;
 
        control = ao2_alloc(sizeof(*control), control_dtor);
@@ -109,28 +107,29 @@ struct stasis_app_control *control_create(struct ast_channel *channel, struct st
                return NULL;
        }
 
-       control->app = ao2_bump(app);
+       AST_LIST_HEAD_INIT(&control->add_rules);
+       AST_LIST_HEAD_INIT(&control->remove_rules);
 
        res = ast_cond_init(&control->wait_cond, NULL);
        if (res != 0) {
                ast_log(LOG_ERROR, "Error initializing ast_cond_t: %s\n",
                        strerror(errno));
+               ao2_ref(control, -1);
                return NULL;
        }
 
+       control->app = ao2_bump(app);
+
+       ast_channel_ref(channel);
+       control->channel = channel;
+
        control->command_queue = ao2_container_alloc_list(
                AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
-
        if (!control->command_queue) {
+               ao2_ref(control, -1);
                return NULL;
        }
 
-       control->channel = channel;
-
-       AST_LIST_HEAD_INIT(&control->add_rules);
-       AST_LIST_HEAD_INIT(&control->remove_rules);
-
-       ao2_ref(control, +1);
        return control;
 }
 
@@ -668,8 +667,7 @@ void stasis_app_control_silence_start(struct stasis_app_control *control)
        stasis_app_send_command_async(control, app_control_silence_start, NULL, NULL);
 }
 
-static int app_control_silence_stop(struct stasis_app_control *control,
-       struct ast_channel *chan, void *data)
+void control_silence_stop_now(struct stasis_app_control *control)
 {
        if (control->silgen) {
                ast_debug(3, "%s: Stopping silence generator\n",
@@ -678,7 +676,12 @@ static int app_control_silence_stop(struct stasis_app_control *control,
                        control->channel, control->silgen);
                control->silgen = NULL;
        }
+}
 
+static int app_control_silence_stop(struct stasis_app_control *control,
+       struct ast_channel *chan, void *data)
+{
+       control_silence_stop_now(control);
        return 0;
 }
 
index a139f82e4303cd7aaf005de91d86cf7300f3f855..d053a35f7c3aa98a44817841d841c43658833cda 100644 (file)
@@ -108,5 +108,13 @@ int control_add_channel_to_bridge(
        struct stasis_app_control *control,
        struct ast_channel *chan, void *obj);
 
+/*!
+ * \brief Stop playing silence to a channel right now.
+ * \since 13.9.0
+ *
+ * \param control The control for chan
+ */
+void control_silence_stop_now(struct stasis_app_control *control);
+
 
 #endif /* _ASTERISK_RES_STASIS_CONTROL_H */