Merged revisions 336977 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.8

........
  r336977 | rmudgett | 2011-09-20 13:12:17 -0500 (Tue, 20 Sep 2011) | 21 lines
  
  Fix deadlock from not releasing SS7 linkset lock.
  
  sig_ss7_hangup() failed to release the SS7 linkset lock if the call had
  the alreadyhungup flag set.
  
  * Made unlock the SS7 linkset lock in sig_ss7_hangup() if the
  alreadyhungup flag is set.
  
  * Made ss7_start_call() not hold any locks while creating the channel for
  an incoming call to prevent deadlock.
  
  * Made ss7_grab() a void function, since it could never fail, to simplify
  calling code.
  
  * Made obtain the channel lock to do softhangup in some places.
  
  Patches:
        jira_ast_668_v1.8.patch (license #5621) patch uploaded by rmudgett
  
  JIRA AST-668
........


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/10@336978 65c4cc65-6c06-0410-ace0-fbb531ad65f3
10-digiumphones
Richard Mudgett 14 years ago
parent a31b5ce87e
commit 4fdae215bd

@ -454,20 +454,27 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
}
/*
* Release the SS7 lock while we create the channel
* so other threads can send messages.
* Release the SS7 lock while we create the channel so other
* threads can send messages. We must also release the private
* lock to prevent deadlock while creating the channel.
*/
ast_mutex_unlock(&linkset->lock);
sig_ss7_unlock_private(p);
c = sig_ss7_new_ast_channel(p, AST_STATE_RING, law, 0, p->exten, NULL);
if (!c) {
ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
ast_mutex_lock(&linkset->lock);
sig_ss7_lock_private(p);
isup_rel(linkset->ss7, p->ss7call, -1);
p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
p->alreadyhungup = 1;
return;
}
/* Hold the channel and private lock while we setup the channel. */
ast_channel_lock(c);
sig_ss7_lock_private(p);
sig_ss7_set_echocanceller(p, 1);
/*
@ -549,13 +556,19 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
p->generic_name[0] = 0;
}
sig_ss7_unlock_private(p);
ast_channel_unlock(c);
if (ast_pbx_start(c)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s (CIC %d)\n", c->name, p->cic);
ast_hangup(c);
} else {
ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
}
/* Must return with linkset and private lock. */
ast_mutex_lock(&linkset->lock);
sig_ss7_lock_private(p);
}
static void ss7_apply_plan_to_number(char *buf, size_t size, const struct sig_ss7_linkset *ss7, const char *number, const unsigned nai)
@ -739,9 +752,12 @@ void *ss7_linkset(void *data)
sig_ss7_set_remotelyblocked(p, 0);
dpc = p->dpc;
isup_set_call_dpc(e->rsc.call, dpc);
sig_ss7_lock_owner(linkset, chanpos);
p->ss7call = NULL;
if (p->owner)
p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
if (p->owner) {
ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
ast_channel_unlock(p->owner);
}
sig_ss7_unlock_private(p);
isup_rlc(ss7, e->rsc.call);
break;
@ -912,9 +928,11 @@ void *ss7_linkset(void *data)
}
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
sig_ss7_lock_owner(linkset, chanpos);
if (p->owner) {
p->owner->hangupcause = e->rel.cause;
p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
ast_channel_unlock(p->owner);
} else {
ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic);
}
@ -1088,8 +1106,8 @@ void *ss7_linkset(void *data)
else
ast_log(LOG_NOTICE, "Received RLC out and we haven't sent REL. Ignoring.\n");
sig_ss7_unlock_private(p);
}
break;
}
break;
case ISUP_EVENT_FAA:
chanpos = ss7_find_cic(linkset, e->faa.cic, e->faa.opc);
if (chanpos < 0) {
@ -1122,7 +1140,7 @@ static inline void ss7_rel(struct sig_ss7_linkset *ss7)
ast_mutex_unlock(&ss7->lock);
}
static inline int ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7)
static void ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7)
{
int res;
/* Grab the lock first */
@ -1135,7 +1153,6 @@ static inline int ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7
/* Then break the poll */
if (ss7->master != AST_PTHREADT_NULL)
pthread_kill(ss7->master, SIGURG);
return 0;
}
/*!
@ -1302,10 +1319,7 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, char *rdest)
l = NULL;
}
if (ss7_grab(p, p->ss7)) {
ast_log(LOG_WARNING, "Failed to grab SS7!\n");
return -1;
}
ss7_grab(p, p->ss7);
p->ss7call = isup_new_call(p->ss7->ss7);
if (!p->ss7call) {
@ -1428,24 +1442,22 @@ int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
p->exten[0] = '\0';
/* Perform low level hangup if no owner left */
if (p->ss7call) {
if (!ss7_grab(p, p->ss7)) {
if (!p->alreadyhungup) {
const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
int icause = ast->hangupcause ? ast->hangupcause : -1;
if (cause) {
if (atoi(cause))
icause = atoi(cause);
ss7_grab(p, p->ss7);
if (!p->alreadyhungup) {
const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
int icause = ast->hangupcause ? ast->hangupcause : -1;
if (cause) {
if (atoi(cause)) {
icause = atoi(cause);
}
isup_rel(p->ss7->ss7, p->ss7call, icause);
ss7_rel(p->ss7);
p->alreadyhungup = 1;
} else
ast_log(LOG_WARNING, "Trying to hangup twice!\n");
}
isup_rel(p->ss7->ss7, p->ss7call, icause);
p->alreadyhungup = 1;
} else {
ast_log(LOG_WARNING, "Unable to grab SS7 on CIC %d\n", p->cic);
res = -1;
ast_log(LOG_WARNING, "Trying to hangup twice!\n");
}
ss7_rel(p->ss7);
}
return res;
@ -1465,16 +1477,12 @@ int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast)
{
int res;
if (!ss7_grab(p, p->ss7)) {
if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
}
res = isup_anm(p->ss7->ss7, p->ss7call);
ss7_rel(p->ss7);
} else {
ast_log(LOG_WARNING, "Unable to grab SS7 on span %d\n", p->ss7->span);
res = -1;
ss7_grab(p, p->ss7);
if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
}
res = isup_anm(p->ss7->ss7, p->ss7call);
ss7_rel(p->ss7);
return res;
}

Loading…
Cancel
Save