ConfBridge does not handle hangup properly

When playing back a prompt to a channel, confbridge neglects to check for
hangup events causing lockup condititions for hangups that occur before
actually joining the conference.  This change ensures that the user is removed 
from the conference in the event of a premature hangup.

Review: https://reviewboard.asterisk.org/r/1277/


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@324305 65c4cc65-6c06-0410-ace0-fbb531ad65f3
certified/1.8.6
Kinsey Moore 14 years ago
parent ce2e420902
commit a9a8c0fa05

@ -198,30 +198,31 @@ static int conference_bridge_cmp_cb(void *obj, void *arg, int flags)
* \param conference_bridge Conference bridge to peek at
* \param conference_bridge_user Caller
*
* \return Returns nothing
* \return Returns 0 on success, -1 if the user hung up
*/
static void announce_user_count(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
static int announce_user_count(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
{
if (conference_bridge->users == 1) {
/* Awww we are the only person in the conference bridge */
return;
return 0;
} else if (conference_bridge->users == 2) {
/* Eep, there is one other person */
if (ast_stream_and_wait(conference_bridge_user->chan, "conf-onlyone", "")) {
return;
return -1;
}
} else {
/* Alas multiple others in here */
if (ast_stream_and_wait(conference_bridge_user->chan, "conf-thereare", "")) {
return;
return -1;
}
if (ast_say_number(conference_bridge_user->chan, conference_bridge->users - 1, "", conference_bridge_user->chan->language, NULL)) {
return;
return -1;
}
if (ast_stream_and_wait(conference_bridge_user->chan, "conf-otherinparty", "")) {
return;
return -1;
}
}
return 0;
}
/*!
@ -231,15 +232,17 @@ static void announce_user_count(struct conference_bridge *conference_bridge, str
* \param chan Channel to play audio prompt to
* \param file Prompt to play
*
* \return Returns nothing
* \return Returns 0 on success, -1 if the user hung up
*
* \note This function assumes that conference_bridge is locked
*/
static void play_prompt_to_channel(struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file)
static int play_prompt_to_channel(struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file)
{
int res;
ao2_unlock(conference_bridge);
ast_stream_and_wait(chan, file, "");
res = ast_stream_and_wait(chan, file, "");
ao2_lock(conference_bridge);
return res;
}
/*!
@ -248,16 +251,16 @@ static void play_prompt_to_channel(struct conference_bridge *conference_bridge,
* \param conference_bridge Conference bridge being joined
* \param conference_bridge_user Conference bridge user joining
*
* \return Returns nothing
* \return Returns 0 on success, -1 if the user hung up
*/
static void post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
static int post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
{
if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER)) {
struct conference_bridge_user *other_conference_bridge_user = NULL;
/* If we are not the first marked user to join just bail out now */
if (conference_bridge->markedusers >= 2) {
return;
return 0;
}
/* Iterate through every participant stopping MOH on them if need be */
@ -291,13 +294,16 @@ static void post_join_marked(struct conference_bridge *conference_bridge, struct
} else {
/* If a marked user already exists in the conference bridge we can just bail out now */
if (conference_bridge->markedusers) {
return;
return 0;
}
/* Be sure we are muted so we can't talk to anybody else waiting */
conference_bridge_user->features.mute = 1;
/* If we have not been quieted play back that they are waiting for the leader */
if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET)) {
play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, "conf-waitforleader");
if (play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, "conf-waitforleader")) {
/* user hung up while the sound was playing */
return -1;
}
}
/* Start music on hold if needed */
/* We need to recheck the markedusers value here. play_prompt_to_channel unlocks the conference bridge, potentially
@ -307,6 +313,7 @@ static void post_join_marked(struct conference_bridge *conference_bridge, struct
ast_moh_start(conference_bridge_user->chan, conference_bridge_user->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
}
}
return 0;
}
/*!
@ -315,15 +322,18 @@ static void post_join_marked(struct conference_bridge *conference_bridge, struct
* \param conference_bridge Conference bridge being joined
* \param conference_bridge_user Conference bridge user joining
*
* \return Returns nothing
* \return Returns 0 on success, -1 if the user hung up
*/
static void post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
static int post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
{
/* Play back audio prompt and start MOH if need be if we are the first participant */
if (conference_bridge->users == 1) {
/* If audio prompts have not been quieted or this prompt quieted play it on out */
if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET | OPTION_NOONLYPERSON)) {
play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, "conf-onlyperson");
if (play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, "conf-onlyperson")) {
/* user hung up while the sound was playing */
return -1;
}
}
/* If we need to start music on hold on the channel do so now */
/* We need to re-check the number of users in the conference bridge here because another conference bridge
@ -332,13 +342,16 @@ static void post_join_unmarked(struct conference_bridge *conference_bridge, stru
if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->flags, OPTION_MUSICONHOLD)) {
ast_moh_start(conference_bridge_user->chan, conference_bridge_user->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
}
return;
return 0;
}
/* Announce number of users if need be */
if (ast_test_flag(&conference_bridge_user->flags, OPTION_ANNOUNCEUSERCOUNT)) {
ao2_unlock(conference_bridge);
announce_user_count(conference_bridge, conference_bridge_user);
if (announce_user_count(conference_bridge, conference_bridge_user)) {
ao2_lock(conference_bridge);
return -1;
}
ao2_lock(conference_bridge);
}
@ -352,6 +365,7 @@ static void post_join_unmarked(struct conference_bridge *conference_bridge, stru
ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
}
}
return 0;
}
/*!
@ -383,6 +397,8 @@ static void destroy_conference_bridge(void *obj)
}
}
static void leave_conference_bridge(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user);
/*!
* \brief Join a conference bridge
*
@ -470,9 +486,17 @@ static struct conference_bridge *join_conference_bridge(const char *name, struct
/* If the caller is a marked user or is waiting for a marked user to enter pass 'em off, otherwise pass them off to do regular joining stuff */
if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER | OPTION_WAITMARKED)) {
post_join_marked(conference_bridge, conference_bridge_user);
if (post_join_marked(conference_bridge, conference_bridge_user)) {
ao2_unlock(conference_bridge);
leave_conference_bridge(conference_bridge, conference_bridge_user);
return NULL;
}
} else {
post_join_unmarked(conference_bridge, conference_bridge_user);
if (post_join_unmarked(conference_bridge, conference_bridge_user)) {
ao2_unlock(conference_bridge);
leave_conference_bridge(conference_bridge, conference_bridge_user);
return NULL;
}
}
ao2_unlock(conference_bridge);

Loading…
Cancel
Save