Merged revisions 104841 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r104841 | mmichelson | 2008-02-27 15:49:20 -0600 (Wed, 27 Feb 2008) | 17 lines Two fixes: 1. Make the list of ast_dial_channels a lockable list. This is because in some cases, the ast_dial may exist in multiple threads due to asynchronous execution of its application, and I found some cases where race conditions could exist. 2. Check in ast_dial_join to be sure that the channel still exists before attempting to lock it, since it could have gotten hung up but the is_running_app flag on the ast_dial_channel may not have been cleared yet. (closes issue #12038) Reported by: jvandal Patches: 12038v2.patch uploaded by putnopvut (license 60) Tested by: jvandal ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@105060 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
62c63a8412
commit
beb7a540c1
34
main/dial.c
34
main/dial.c
|
@ -46,7 +46,7 @@ struct ast_dial {
|
|||
enum ast_dial_result state; /*!< Status of dial */
|
||||
void *options[AST_DIAL_OPTION_MAX]; /*!< Global options */
|
||||
ast_dial_state_callback state_callback; /*!< Status callback */
|
||||
AST_LIST_HEAD_NOLOCK(, ast_dial_channel) channels; /*!< Channels being dialed */
|
||||
AST_LIST_HEAD(, ast_dial_channel) channels; /*!< Channels being dialed */
|
||||
pthread_t thread; /*!< Thread (if running in async) */
|
||||
ast_mutex_t lock; /*! Lock to protect the thread information above */
|
||||
};
|
||||
|
@ -203,7 +203,7 @@ struct ast_dial *ast_dial_create(void)
|
|||
return NULL;
|
||||
|
||||
/* Initialize list of channels */
|
||||
AST_LIST_HEAD_INIT_NOLOCK(&dial->channels);
|
||||
AST_LIST_HEAD_INIT(&dial->channels);
|
||||
|
||||
/* Initialize thread to NULL */
|
||||
dial->thread = AST_PTHREADT_NULL;
|
||||
|
@ -312,6 +312,7 @@ static int begin_dial(struct ast_dial *dial, struct ast_channel *chan)
|
|||
int success = 0;
|
||||
|
||||
/* Iterate through channel list, requesting and calling each one */
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_TRAVERSE(&dial->channels, channel, list) {
|
||||
success += begin_dial_channel(channel, chan);
|
||||
}
|
||||
|
@ -348,6 +349,7 @@ static int handle_call_forward(struct ast_dial *dial, struct ast_dial_channel *c
|
|||
/* Update the dial channel with the new destination information */
|
||||
channel->tech = ast_strdup(tech);
|
||||
channel->device = ast_strdup(device);
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
|
||||
/* Finally give it a go... send it out into the world */
|
||||
begin_dial_channel(channel, chan);
|
||||
|
@ -363,10 +365,12 @@ static struct ast_dial_channel *find_relative_dial_channel(struct ast_dial *dial
|
|||
{
|
||||
struct ast_dial_channel *channel = NULL;
|
||||
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_TRAVERSE(&dial->channels, channel, list) {
|
||||
if (channel->owner == owner)
|
||||
break;
|
||||
}
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
@ -386,8 +390,10 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel
|
|||
switch (fr->subclass) {
|
||||
case AST_CONTROL_ANSWER:
|
||||
ast_verb(3, "%s answered %s\n", channel->owner->name, chan->name);
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_REMOVE(&dial->channels, channel, list);
|
||||
AST_LIST_INSERT_HEAD(&dial->channels, channel, list);
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
set_state(dial, AST_DIAL_RESULT_ANSWERED);
|
||||
break;
|
||||
case AST_CONTROL_BUSY:
|
||||
|
@ -453,8 +459,10 @@ static void handle_frame_ownerless(struct ast_dial *dial, struct ast_dial_channe
|
|||
switch (fr->subclass) {
|
||||
case AST_CONTROL_ANSWER:
|
||||
ast_verb(3, "%s answered\n", channel->owner->name);
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_REMOVE(&dial->channels, channel, list);
|
||||
AST_LIST_INSERT_HEAD(&dial->channels, channel, list);
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
set_state(dial, AST_DIAL_RESULT_ANSWERED);
|
||||
break;
|
||||
case AST_CONTROL_BUSY:
|
||||
|
@ -557,12 +565,14 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
|
|||
cs[pos++] = chan;
|
||||
|
||||
/* Add channels we are attempting to dial */
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_TRAVERSE(&dial->channels, channel, list) {
|
||||
if (channel->owner) {
|
||||
cs[pos++] = channel->owner;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
|
||||
/* If we have no outbound channels in progress, switch state to unanswered and stop */
|
||||
if (!count) {
|
||||
|
@ -624,6 +634,7 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
|
|||
/* Do post-processing from loop */
|
||||
if (dial->state == AST_DIAL_RESULT_ANSWERED) {
|
||||
/* Hangup everything except that which answered */
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_TRAVERSE(&dial->channels, channel, list) {
|
||||
if (!channel->owner || channel->owner == who)
|
||||
continue;
|
||||
|
@ -632,6 +643,7 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
|
|||
ast_hangup(channel->owner);
|
||||
channel->owner = NULL;
|
||||
}
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
/* If ANSWER_EXEC is enabled as an option, execute application on answered channel */
|
||||
if ((channel = find_relative_dial_channel(dial, who)) && (answer_exec = FIND_RELATIVE_OPTION(dial, channel, AST_DIAL_OPTION_ANSWER_EXEC))) {
|
||||
channel->is_running_app = 1;
|
||||
|
@ -645,6 +657,7 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
|
|||
}
|
||||
} else if (dial->state == AST_DIAL_RESULT_HANGUP) {
|
||||
/* Hangup everything */
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_TRAVERSE(&dial->channels, channel, list) {
|
||||
if (!channel->owner)
|
||||
continue;
|
||||
|
@ -653,6 +666,7 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
|
|||
ast_hangup(channel->owner);
|
||||
channel->owner = NULL;
|
||||
}
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
}
|
||||
|
||||
return dial->state;
|
||||
|
@ -771,15 +785,19 @@ enum ast_dial_result ast_dial_join(struct ast_dial *dial)
|
|||
dial->thread = AST_PTHREADT_STOP;
|
||||
|
||||
/* If the answered channel is running an application we have to soft hangup it, can't just poke the thread */
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
if (AST_LIST_FIRST(&dial->channels)->is_running_app) {
|
||||
struct ast_channel *chan = AST_LIST_FIRST(&dial->channels)->owner;
|
||||
ast_channel_lock(chan);
|
||||
ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
|
||||
ast_channel_unlock(chan);
|
||||
if (chan) {
|
||||
ast_channel_lock(chan);
|
||||
ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
|
||||
ast_channel_unlock(chan);
|
||||
}
|
||||
} else {
|
||||
/* Now we signal it with SIGURG so it will break out of it's waitfor */
|
||||
pthread_kill(thread, SIGURG);
|
||||
}
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
|
||||
/* Yay done with it */
|
||||
ast_mutex_unlock(&dial->lock);
|
||||
|
@ -804,12 +822,14 @@ void ast_dial_hangup(struct ast_dial *dial)
|
|||
if (!dial)
|
||||
return;
|
||||
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_TRAVERSE(&dial->channels, channel, list) {
|
||||
if (channel->owner) {
|
||||
ast_hangup(channel->owner);
|
||||
channel->owner = NULL;
|
||||
}
|
||||
}
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -828,6 +848,7 @@ int ast_dial_destroy(struct ast_dial *dial)
|
|||
return -1;
|
||||
|
||||
/* Hangup and deallocate all the dialed channels */
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&dial->channels, channel, list) {
|
||||
/* Disable any enabled options */
|
||||
for (i = 0; i < AST_DIAL_OPTION_MAX; i++) {
|
||||
|
@ -849,6 +870,7 @@ int ast_dial_destroy(struct ast_dial *dial)
|
|||
ast_free(channel);
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
|
||||
/* Disable any enabled options globally */
|
||||
for (i = 0; i < AST_DIAL_OPTION_MAX; i++) {
|
||||
|
@ -900,10 +922,12 @@ static struct ast_dial_channel *find_dial_channel(struct ast_dial *dial, int num
|
|||
return channel;
|
||||
|
||||
/* Hrm not at the end... looking through the list it is! */
|
||||
AST_LIST_LOCK(&dial->channels);
|
||||
AST_LIST_TRAVERSE(&dial->channels, channel, list) {
|
||||
if (channel->num == num)
|
||||
break;
|
||||
}
|
||||
AST_LIST_UNLOCK(&dial->channels);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue