diff options
author | Richard Mudgett <rmudgett@digium.com> | 2011-09-20 18:20:10 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2011-09-20 18:20:10 +0000 |
commit | b3768f04c326606f75333695fb7ff4f44b523bed (patch) | |
tree | c82adc31ed5960644131e6b7d2b6a3ee35613b67 /channels/sig_ss7.c | |
parent | 8493c463088657a9f00e54c9b9d7c06d3ad881a2 (diff) |
Merged revisions 336978 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/10
................
r336978 | rmudgett | 2011-09-20 13:14:40 -0500 (Tue, 20 Sep 2011) | 28 lines
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/trunk@336988 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels/sig_ss7.c')
-rw-r--r-- | channels/sig_ss7.c | 82 |
1 files changed, 45 insertions, 37 deletions
diff --git a/channels/sig_ss7.c b/channels/sig_ss7.c index 3f7ea2a97..915ccedc5 100644 --- a/channels/sig_ss7.c +++ b/channels/sig_ss7.c @@ -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; } |