summaryrefslogtreecommitdiff
path: root/channels/sig_ss7.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2011-09-20 18:20:10 +0000
committerRichard Mudgett <rmudgett@digium.com>2011-09-20 18:20:10 +0000
commitb3768f04c326606f75333695fb7ff4f44b523bed (patch)
treec82adc31ed5960644131e6b7d2b6a3ee35613b67 /channels/sig_ss7.c
parent8493c463088657a9f00e54c9b9d7c06d3ad881a2 (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.c82
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;
}