Skip to content

Commit 79562cf

Browse files
InterLinked1Friendly Automation
authored andcommitted
sla: Prevent deadlock and crash due to autoservicing.
SLAStation currently autoservices the station channel before creating a thread to actually dial the trunk. This leads to duplicate servicing of the channel which causes assertions, deadlocks, crashes, and moreover not the correct behavior. Removing the autoservice prevents the crash, but if the station hangs up before the trunk answers, the call hangs since the hangup was never serviced on the channel. This is fixed by not autoservicing the channel, but instead servicing it in the thread dialing the trunk, since it is doing so synchronously to begin with. Instead of sleeping for 100ms in a loop, we simply use the channel for timing, and abort if it disappears. The same issue also occurs with SLATrunk when a call is answered, because ast_answer invokes ast_waitfor_nandfds. Thus, we use ast_raw_answer instead which does not cause any conflict and allows the call to be answered normally without thread blocking issues. ASTERISK-29998 #close Change-Id: Icc237d50354b5910000d2305901e86d2c87bb9d8
1 parent 2cfb3df commit 79562cf

File tree

1 file changed

+17
-7
lines changed

1 file changed

+17
-7
lines changed

apps/app_meetme.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6149,7 +6149,7 @@ struct run_station_args {
61496149

61506150
static void answer_trunk_chan(struct ast_channel *chan)
61516151
{
6152-
ast_answer(chan);
6152+
ast_raw_answer(chan);
61536153
ast_indicate(chan, -1);
61546154
}
61556155

@@ -6994,8 +6994,18 @@ static void *dial_trunk(void *data)
69946994
return NULL;
69956995
}
69966996

6997-
for (;;) {
6997+
/* Wait for dial to end, while servicing the channel */
6998+
while (ast_waitfor(trunk_ref->chan, 100)) {
69986999
unsigned int done = 0;
7000+
struct ast_frame *fr = ast_read(trunk_ref->chan);
7001+
7002+
if (!fr) {
7003+
ast_debug(1, "Channel %s did not return a frame, must have hung up\n", ast_channel_name(trunk_ref->chan));
7004+
done = 1;
7005+
break;
7006+
}
7007+
ast_frfree(fr); /* Ignore while dialing */
7008+
69997009
switch ((dial_res = ast_dial_state(dial))) {
70007010
case AST_DIAL_RESULT_ANSWERED:
70017011
trunk_ref->trunk->chan = ast_dial_answered(dial);
@@ -7032,8 +7042,6 @@ static void *dial_trunk(void *data)
70327042
last_state = current_state;
70337043
}
70347044

7035-
/* avoid tight loop... sleep for 1/10th second */
7036-
ast_safe_sleep(trunk_ref->chan, 100);
70377045
}
70387046

70397047
if (!trunk_ref->trunk->chan) {
@@ -7192,8 +7200,10 @@ static int sla_station_exec(struct ast_channel *chan, const char *data)
71927200
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
71937201
/* Create a thread to dial the trunk and dump it into the conference.
71947202
* However, we want to wait until the trunk has been dialed and the
7195-
* conference is created before continuing on here. */
7196-
ast_autoservice_start(chan);
7203+
* conference is created before continuing on here.
7204+
* Don't autoservice the channel or we'll have multiple threads
7205+
* handling it. dial_trunk services the channel.
7206+
*/
71977207
ast_mutex_init(&cond_lock);
71987208
ast_cond_init(&cond, NULL);
71997209
ast_mutex_lock(&cond_lock);
@@ -7202,7 +7212,7 @@ static int sla_station_exec(struct ast_channel *chan, const char *data)
72027212
ast_mutex_unlock(&cond_lock);
72037213
ast_mutex_destroy(&cond_lock);
72047214
ast_cond_destroy(&cond);
7205-
ast_autoservice_stop(chan);
7215+
72067216
if (!trunk_ref->trunk->chan) {
72077217
ast_debug(1, "Trunk didn't get created. chan: %lx\n", (unsigned long) trunk_ref->trunk->chan);
72087218
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");

0 commit comments

Comments
 (0)