[asterisk-commits] rmudgett: branch rmudgett/bch_shift_v1.6.2 r311684 - in /team/rmudgett/bch_sh...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Mar 25 15:03:50 CDT 2011
Author: rmudgett
Date: Fri Mar 25 15:03:46 2011
New Revision: 311684
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=311684
Log:
Merged revisions 311500 via svnmerge from
https://origsvn.digium.com/svn/asterisk/team/rmudgett/bch_shift_v1.8
........
r311500 | rmudgett | 2011-03-22 10:42:37 -0500 (Tue, 22 Mar 2011) | 2 lines
Fix deadlock and internal B channel allocation race between in/out going calls.
........
Modified:
team/rmudgett/bch_shift_v1.6.2/ (props changed)
team/rmudgett/bch_shift_v1.6.2/channels/chan_dahdi.c
Propchange: team/rmudgett/bch_shift_v1.6.2/
('automerge' removed)
Propchange: team/rmudgett/bch_shift_v1.6.2/
------------------------------------------------------------------------------
--- bch_shift_v1.8-integrated (original)
+++ bch_shift_v1.8-integrated Fri Mar 25 15:03:46 2011
@@ -1,1 +1,1 @@
-/team/rmudgett/bch_shift_v1.8:1-311499
+/team/rmudgett/bch_shift_v1.8:1-311500
Modified: team/rmudgett/bch_shift_v1.6.2/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bch_shift_v1.6.2/channels/chan_dahdi.c?view=diff&rev=311684&r1=311683&r2=311684
==============================================================================
--- team/rmudgett/bch_shift_v1.6.2/channels/chan_dahdi.c (original)
+++ team/rmudgett/bch_shift_v1.6.2/channels/chan_dahdi.c Fri Mar 25 15:03:46 2011
@@ -364,6 +364,11 @@
static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
static int dahdi_sendtext(struct ast_channel *c, const char *text);
+
+#define SIG_PRI_LIB_HANDLE_CASES \
+ SIG_PRI: \
+ case SIG_BRI: \
+ case SIG_BRI_PTMP
static void mwi_event_cb(const struct ast_event *event, void *userdata)
{
@@ -817,6 +822,19 @@
unsigned int inalarm:1;
/*! \brief TRUE if TDD in MATE mode */
unsigned int mate:1;
+#if defined(HAVE_PRI)
+ /*!
+ * \brief TRUE when this channel is allocated.
+ *
+ * \details
+ * Needed to hold an outgoing channel allocation before the
+ * owner pointer is created.
+ *
+ * \note This is one of several items to check to see if a
+ * channel is available for use.
+ */
+ unsigned int allocated:1;
+#endif /* defined(HAVE_PRI) */
/*! \brief TRUE if we originated the call leg. */
unsigned int outgoing:1;
/* unsigned int overlapdial:1; unused and potentially confusing */
@@ -4597,6 +4615,9 @@
p->faxhandled = 0;
p->pulsedial = 0;
p->onhooktime = time(NULL);
+#if defined(HAVE_PRI)
+ p->allocated = 0;
+#endif /* defined(HAVE_PRI) */
#if defined(HAVE_PRI) || defined(HAVE_SS7)
p->dialing = 0;
p->progress = 0;
@@ -11095,6 +11116,86 @@
return tmp;
}
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Determine if a private channel structure is in use.
+ * \since 1.8
+ *
+ * \param pvt Channel to determine if in use.
+ *
+ * \return TRUE if the channel is in use.
+ */
+static int sig_pri_is_chan_in_use(struct dahdi_pvt *pvt)
+{
+ return pvt->owner || pvt->call || pvt->allocated || pvt->resetting || pvt->inalarm;
+}
+#endif /* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Determine if a private channel structure is available.
+ * \since 1.8
+ *
+ * \param pvt Channel to determine if available.
+ *
+ * \return TRUE if the channel is available.
+ */
+static int sig_pri_is_chan_available(struct dahdi_pvt *pvt)
+{
+ return !sig_pri_is_chan_in_use(pvt);
+}
+#endif /* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Simple check if the channel is available to use.
+ * \since 1.8
+ *
+ * \param pvt Private channel control structure.
+ *
+ * \retval 0 Interface not available.
+ * \retval 1 Interface is available.
+ */
+static int sig_pri_available_check(struct dahdi_pvt *pvt)
+{
+ /*
+ * If interface is available for use
+ * then the channel is available.
+ */
+ if (sig_pri_is_chan_available(pvt)) {
+ return 1;
+ }
+ return 0;
+}
+#endif /* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+static int sig_pri_available(struct dahdi_pvt *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ struct dahdi_pri *pri;
+
+ if (!p->pri) {
+ /* Something is wrong here. A PRI channel without the pri pointer? */
+ return 0;
+ }
+ pri = p->pri;
+
+ ast_mutex_lock(&pri->lock);
+ if (sig_pri_available_check(p)) {
+ p->allocated = 1;
+ ast_mutex_unlock(&pri->lock);
+ return 1;
+ }
+
+ ast_mutex_unlock(&pri->lock);
+ return 0;
+}
+#endif /* defined(HAVE_PRI) */
+
static inline int available(struct dahdi_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
{
int res;
@@ -11112,6 +11213,16 @@
return 0;
*channelmatched = 1;
}
+
+#if defined(HAVE_PRI)
+ switch (p->sig) {
+ case SIG_PRI_LIB_HANDLE_CASES:
+ return sig_pri_available(p);
+ default:
+ break;
+ }
+#endif /* defined(HAVE_PRI) */
+
/* We're at least busy at this point */
if (busy) {
if ((p->sig == SIG_FXOKS) || (p->sig == SIG_FXOLS) || (p->sig == SIG_FXOGS))
@@ -11129,15 +11240,6 @@
/* If no owner definitely available */
if (!p->owner) {
-#ifdef HAVE_PRI
- /* Trust PRI */
- if (p->pri) {
- if (p->resetting || p->call)
- return 0;
- else
- return 1;
- }
-#endif
#ifdef HAVE_SS7
/* Trust SS7 */
if (p->ss7) {
@@ -11265,6 +11367,18 @@
}
#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Find an empty B-channel interface to use.
+ *
+ * \param pri PRI span control structure.
+ * \param backwards TRUE if the search starts from higher channels.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval array-index into private pointer array on success.
+ * \retval -1 on error.
+ */
static int pri_find_empty_chan(struct dahdi_pri *pri, int backwards)
{
int x;
@@ -11277,7 +11391,8 @@
break;
if (!backwards && (x >= pri->numchans))
break;
- if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
+ if (pri->pvts[x]
+ && sig_pri_is_chan_available(pri->pvts[x])) {
ast_debug(1, "Found empty available channel %d/%d\n",
pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
return x;
@@ -11484,6 +11599,19 @@
tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, 0);
if (!tmp) {
p->outgoing = 0;
+#if defined(HAVE_PRI)
+ switch (p->sig) {
+ case SIG_PRI_LIB_HANDLE_CASES:
+ /*
+ * This should be the last thing to clear when we are done with
+ * the channel.
+ */
+ p->allocated = 0;
+ break;
+ default:
+ break;
+ }
+#endif /* defined(HAVE_PRI) */
}
#ifdef HAVE_PRI
if (p->bearer) {
@@ -12751,7 +12879,7 @@
ast_verb(3, "Moving call (%s) from channel %d to %d.\n",
old->owner ? old->owner->name : "",
old->channel, new->channel);
- if (new->owner) {
+ if (!sig_pri_is_chan_available(new)) {
ast_log(LOG_WARNING,
"Can't move call (%s) from channel %d to %d. It is already in use.\n",
old->owner ? old->owner->name : "",
@@ -12790,11 +12918,13 @@
new->alreadyhungup = old->alreadyhungup;
new->isidlecall = old->isidlecall;
new->progress = old->progress;
+ new->allocated = old->allocated;
new->outgoing = old->outgoing;
new->digital = old->digital;
old->alreadyhungup = 0;
old->isidlecall = 0;
old->progress = 0;
+ old->allocated = 0;
old->outgoing = 0;
old->digital = 0;
@@ -13024,14 +13154,25 @@
#endif /* defined(HAVE_PRI) */
#if defined(HAVE_PRI)
-static int pri_check_restart(struct dahdi_pri *pri)
-{
- do {
- pri->resetpos++;
- } while ((pri->resetpos < pri->numchans) &&
- (!pri->pvts[pri->resetpos] ||
- pri->pvts[pri->resetpos]->call ||
- pri->pvts[pri->resetpos]->resetting));
+/*!
+ * \internal
+ * \brief Restart the next channel we think is idle on the span.
+ *
+ * \param pri PRI span control structure.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void pri_check_restart(struct dahdi_pri *pri)
+{
+ for (++pri->resetpos; pri->resetpos < pri->numchans; ++pri->resetpos) {
+ if (!pri->pvts[pri->resetpos]
+ || sig_pri_is_chan_in_use(pri->pvts[pri->resetpos])) {
+ continue;
+ }
+ break;
+ }
if (pri->resetpos < pri->numchans) {
/* Mark the channel as resetting and restart it */
pri->pvts[pri->resetpos]->resetting = 1;
@@ -13040,7 +13181,6 @@
pri->resetting = 0;
time(&pri->lastreset);
}
- return 0;
}
#endif /* defined(HAVE_PRI) */
@@ -13189,8 +13329,9 @@
ast_mutex_lock(&pri->lock);
if ((pri->switchtype != PRI_SWITCH_GR303_TMC) && (pri->sig != SIG_BRI_PTMP) && (pri->resetinterval > 0)) {
if (pri->resetting && pri_is_up(pri)) {
- if (pri->resetpos < 0)
+ if (pri->resetpos < 0) {
pri_check_restart(pri);
+ }
} else {
if (!pri->resetting && (t - pri->lastreset) >= pri->resetinterval) {
pri->resetting = 1;
@@ -13204,30 +13345,39 @@
haveidles = 0;
activeidles = 0;
for (x = pri->numchans; x >= 0; x--) {
- if (pri->pvts[x] && !pri->pvts[x]->owner &&
- !pri->pvts[x]->call) {
- if (haveidles < pri->minunused) {
- haveidles++;
- } else if (!pri->pvts[x]->resetting) {
- nextidle = x;
- break;
+ if (pri->pvts[x]) {
+ if (sig_pri_is_chan_available(pri->pvts[x])) {
+ if (haveidles < pri->minunused) {
+ haveidles++;
+ } else {
+ nextidle = x;
+ break;
+ }
+ } else if (pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
+ activeidles++;
}
- } else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
- activeidles++;
+ }
}
if (nextidle > -1) {
if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
/* Don't create a new idle call more than once per second */
snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
+ /*
+ * Release the PRI lock while we create the channel so other
+ * threads can send D channel messages.
+ */
+ ast_mutex_unlock(&pri->lock);
idle = dahdi_request("DAHDI", AST_FORMAT_ULAW, idlen, &cause);
+ ast_mutex_lock(&pri->lock);
if (idle) {
pri->pvts[nextidle]->isidlecall = 1;
if (ast_pthread_create_background(&p, NULL, do_idle_thread, idle)) {
ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
- dahdi_hangup(idle);
+ ast_hangup(idle);
}
- } else
+ } else {
ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
+ }
lastidle = ast_tvnow();
}
} else if ((haveidles < pri->minunused) &&
@@ -13503,10 +13653,40 @@
break;
case PRI_EVENT_RING:
crv = NULL;
- if (e->ring.channel == -1) {
+ if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF) {
+ /* Any channel requested. */
chanpos = pri_find_empty_chan(pri, 1);
+ } else if (PRI_CHANNEL(e->ring.channel) == 0x00) {
+ /* No channel specified. */
+ {
+ /* We will not accept incoming call waiting calls. */
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INCOMPATIBLE_DESTINATION);
+ break;
+ }
} else {
+ /* A channel is specified. */
chanpos = pri_find_principle(pri, e->ring.channel);
+ if (chanpos < 0) {
+ ast_log(LOG_WARNING,
+ "Span %d: SETUP on unconfigured channel %d/%d\n",
+ pri->span, PRI_SPAN(e->ring.channel),
+ PRI_CHANNEL(e->ring.channel));
+ } else if (!sig_pri_is_chan_available(pri->pvts[chanpos])) {
+ /* Libpri has already filtered out duplicate SETUPs anyway. */
+ if (pri->pvts[chanpos]->call == e->ring.call) {
+ ast_log(LOG_WARNING,
+ "Span %d: Ignoring duplicate SETUP on channel %d/%d\n",
+ pri->span, PRI_SPAN(e->ring.channel),
+ PRI_CHANNEL(e->ring.channel));
+ break;
+ }
+ /* This is where we handle initial glare */
+ ast_debug(1,
+ "Span %d: SETUP requested unavailable channel %d/%d. Attempting to renegotiate.\n",
+ pri->span, PRI_SPAN(e->ring.channel),
+ PRI_CHANNEL(e->ring.channel));
+ chanpos = -1;
+ }
/*!
* Define to make always pick a channel if allowed. Useful for
* testing channel shifting.
@@ -13515,284 +13695,287 @@
#define ALWAYS_PICK_CHANNEL 1 //BUGBUG
#if defined(ALWAYS_PICK_CHANNEL)
if (e->ring.flexible) {
+ chanpos = -1;
+ }
+#endif /* defined(ALWAYS_PICK_CHANNEL) */
+ if (chanpos < 0 && e->ring.flexible) {
+ /* We can try to pick another channel. */
chanpos = pri_find_empty_chan(pri, 1);
}
-#endif /* defined(ALWAYS_PICK_CHANNEL) */
- }
- /* if no channel specified find one empty */
+ }
if (chanpos < 0) {
- ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+ if (e->ring.flexible) {
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+ } else {
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+ }
+ break;
+ }
+
+ ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+ /* Should be safe to lock CRV AFAIK while bearer is still locked */
+ crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
+ if (crv)
+ ast_mutex_lock(&crv->lock);
+ if (!crv || crv->owner) {
+ pri->pvts[chanpos]->call = NULL;
+ if (crv) {
+ if (crv->owner)
+ crv->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+ ast_log(LOG_WARNING, "Call received for busy CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
+ } else
+ ast_log(LOG_NOTICE, "Call received for unconfigured CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE);
+ if (crv)
+ ast_mutex_unlock(&crv->lock);
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ break;
+ }
+ }
+
+ /* Mark channel as in use so noone else will steal it. */
+ pri->pvts[chanpos]->call = e->ring.call;
+
+ apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
+ if (pri->pvts[chanpos]->use_callerid) {
+ ast_shrink_phone_number(plancallingnum);
+ ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
+#ifdef PRI_ANI
+ if (!ast_strlen_zero(e->ring.callingani)) {
+ apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
+ ast_shrink_phone_number(plancallingani);
+ ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
+ } else {
+ pri->pvts[chanpos]->cid_ani[0] = '\0';
+ }
+#endif
+ ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
+ pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
} else {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- if (pri->pvts[chanpos]->owner) {
- if (pri->pvts[chanpos]->call == e->ring.call) {
- ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n",
- PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- break;
+ pri->pvts[chanpos]->cid_num[0] = '\0';
+ pri->pvts[chanpos]->cid_ani[0] = '\0';
+ pri->pvts[chanpos]->cid_name[0] = '\0';
+ pri->pvts[chanpos]->cid_ton = 0;
+ }
+ apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
+ e->ring.redirectingnum, e->ring.callingplanrdnis);
+
+ /* Set DNID on all incoming calls -- even immediate */
+ ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
+
+ /* If immediate=yes go to s|1 */
+ if (pri->pvts[chanpos]->immediate) {
+ ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
+ pri->pvts[chanpos]->exten[0] = 's';
+ pri->pvts[chanpos]->exten[1] = '\0';
+ }
+ /* Get called number */
+ else if (!ast_strlen_zero(e->ring.callednum)) {
+ ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
+ } else if (pri->overlapdial)
+ pri->pvts[chanpos]->exten[0] = '\0';
+ else {
+ /* Some PRI circuits are set up to send _no_ digits. Handle them as 's'. */
+ pri->pvts[chanpos]->exten[0] = 's';
+ pri->pvts[chanpos]->exten[1] = '\0';
+ }
+ /* No number yet, but received "sending complete"? */
+ if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
+ ast_verb(3, "Going to extension s|1 because of Complete received\n");
+ pri->pvts[chanpos]->exten[0] = 's';
+ pri->pvts[chanpos]->exten[1] = '\0';
+ }
+
+ /* Make sure extension exists (or in overlap dial mode, can exist) */
+ if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
+ ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+ /* Setup law */
+ int law;
+ if (pri->switchtype != PRI_SWITCH_GR303_TMC) {
+ /* Set to audio mode at this point */
+ law = 1;
+ if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
+ ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", pri->pvts[chanpos]->channel, law, strerror(errno));
+ }
+ if (e->ring.layer1 == PRI_LAYER_1_ALAW)
+ law = DAHDI_LAW_ALAW;
+ else
+ law = DAHDI_LAW_MULAW;
+ res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
+ if (res < 0)
+ ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);
+ res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
+ if (res < 0)
+ ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
+ if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
+ /* Just announce proceeding */
+ pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_PROCEEDING;
+ pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
+ } else if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+ pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_CONNECT;
+ pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+ } else {
+ pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_OVERLAP;
+ pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+ }
+ /* Get the use_callingpres state */
+ pri->pvts[chanpos]->callingpres = e->ring.callingpres;
+
+ /* Start PBX */
+ if (!e->ring.complete
+ && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
+ && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+ /*
+ * Release the PRI lock while we create the channel so other
+ * threads can send D channel messages. We must also release
+ * the private lock to prevent deadlock while creating the
+ * channel.
+ */
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ ast_mutex_unlock(&pri->lock);
+ if (crv) {
+ /* Set bearer and such */
+ pri_assign_bearer(crv, pri, pri->pvts[chanpos]);
+ c = dahdi_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
+ pri->pvts[chanpos]->owner = &inuse;
+ ast_debug(1, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
} else {
- /* This is where we handle initial glare */
- ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d. Attempting to renegotiate channel.\n",
- PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- chanpos = -1;
+ c = dahdi_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
}
- }
- if (chanpos > -1)
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- if ((chanpos < 0) && (e->ring.flexible))
- chanpos = pri_find_empty_chan(pri, 1);
- if (chanpos > -1) {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
- /* Should be safe to lock CRV AFAIK while bearer is still locked */
- crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
- if (crv)
- ast_mutex_lock(&crv->lock);
- if (!crv || crv->owner) {
- pri->pvts[chanpos]->call = NULL;
- if (crv) {
- if (crv->owner)
- crv->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- ast_log(LOG_WARNING, "Call received for busy CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
- } else
- ast_log(LOG_NOTICE, "Call received for unconfigured CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE);
- if (crv)
- ast_mutex_unlock(&crv->lock);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- break;
+ ast_mutex_lock(&pri->lock);
+ ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ if (c) {
+ if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+ pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+ }
+ if (e->ring.ani2 >= 0) {
+ snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
+ pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+ pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
+ }
+
+#ifdef SUPPORT_USERUSER
+ if (!ast_strlen_zero(e->ring.useruserinfo)) {
+ pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
+ }
+#endif
+
+ snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
+ pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+ if (e->ring.redirectingreason >= 0)
+ pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
+
+ if (!pri->pvts[chanpos]->digital) {
+ /*
+ * Call has a channel.
+ * Indicate that we are providing dialtone.
+ */
+ pri->pvts[chanpos]->progress = 1;/* No need to send plain PROGRESS again. */
+#ifdef HAVE_PRI_PROG_W_CAUSE
+ pri_progress_with_cause(pri->pri, e->ring.call,
+ PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, -1);/* no cause at all */
+#else
+ pri_progress(pri->pri, e->ring.call,
+ PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+#endif
+ }
}
- }
- pri->pvts[chanpos]->call = e->ring.call;
- apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
- if (pri->pvts[chanpos]->use_callerid) {
- ast_shrink_phone_number(plancallingnum);
- ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
-#ifdef PRI_ANI
- if (!ast_strlen_zero(e->ring.callingani)) {
- apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
- ast_shrink_phone_number(plancallingani);
- ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
+ if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) {
+ ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
+ plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
} else {
- pri->pvts[chanpos]->cid_ani[0] = '\0';
- }
-#endif
- ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
- pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
- } else {
- pri->pvts[chanpos]->cid_num[0] = '\0';
- pri->pvts[chanpos]->cid_ani[0] = '\0';
- pri->pvts[chanpos]->cid_name[0] = '\0';
- pri->pvts[chanpos]->cid_ton = 0;
- }
- apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
- e->ring.redirectingnum, e->ring.callingplanrdnis);
-
- /* Set DNID on all incoming calls -- even immediate */
- ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
-
- /* If immediate=yes go to s|1 */
- if (pri->pvts[chanpos]->immediate) {
- ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
- pri->pvts[chanpos]->exten[0] = 's';
- pri->pvts[chanpos]->exten[1] = '\0';
- }
- /* Get called number */
- else if (!ast_strlen_zero(e->ring.callednum)) {
- ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
- } else if (pri->overlapdial)
- pri->pvts[chanpos]->exten[0] = '\0';
- else {
- /* Some PRI circuits are set up to send _no_ digits. Handle them as 's'. */
- pri->pvts[chanpos]->exten[0] = 's';
- pri->pvts[chanpos]->exten[1] = '\0';
- }
- /* No number yet, but received "sending complete"? */
- if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
- ast_verb(3, "Going to extension s|1 because of Complete received\n");
- pri->pvts[chanpos]->exten[0] = 's';
- pri->pvts[chanpos]->exten[1] = '\0';
- }
-
- /* Make sure extension exists (or in overlap dial mode, can exist) */
- if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
- ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
- /* Setup law */
- int law;
- if (pri->switchtype != PRI_SWITCH_GR303_TMC) {
- /* Set to audio mode at this point */
- law = 1;
- if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
- ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", pri->pvts[chanpos]->channel, law, strerror(errno));
- }
- if (e->ring.layer1 == PRI_LAYER_1_ALAW)
- law = DAHDI_LAW_ALAW;
- else
- law = DAHDI_LAW_MULAW;
- res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);
- res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
- if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
- /* Just announce proceeding */
- pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_PROCEEDING;
- pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
- } else if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
- pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_CONNECT;
- pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
- } else {
- pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_OVERLAP;
- pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
- }
- /* Get the use_callingpres state */
- pri->pvts[chanpos]->callingpres = e->ring.callingpres;
-
- /* Start PBX */
- if (!e->ring.complete
- && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
- && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
- /*
- * Release the PRI lock while we create the channel
- * so other threads can send D channel messages.
- */
- ast_mutex_unlock(&pri->lock);
- if (crv) {
- /* Set bearer and such */
- pri_assign_bearer(crv, pri, pri->pvts[chanpos]);
- c = dahdi_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
- pri->pvts[chanpos]->owner = &inuse;
- ast_debug(1, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
+ ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+ if (c) {
+ /* Avoid deadlock while destroying channel */
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ ast_mutex_unlock(&pri->lock);
+ ast_hangup(c);
+ ast_mutex_lock(&pri->lock);
+ ast_mutex_lock(&pri->pvts[chanpos]->lock);
} else {
- c = dahdi_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
- }
- ast_mutex_lock(&pri->lock);
- if (c) {
- if (!ast_strlen_zero(e->ring.callingsubaddr)) {
- pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
- }
- if (e->ring.ani2 >= 0) {
- snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
- pbx_builtin_setvar_helper(c, "ANI2", ani2str);
- pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
- }
-
-#ifdef SUPPORT_USERUSER
- if (!ast_strlen_zero(e->ring.useruserinfo)) {
- pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
- }
-#endif
-
- snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
- pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
- if (e->ring.redirectingreason >= 0)
- pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
-
- if (!pri->pvts[chanpos]->digital) {
- /*
- * Call has a channel.
- * Indicate that we are providing dialtone.
- */
- pri->pvts[chanpos]->progress = 1;/* No need to send plain PROGRESS again. */
-#ifdef HAVE_PRI_PROG_W_CAUSE
- pri_progress_with_cause(pri->pri, e->ring.call,
- PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, -1);/* no cause at all */
-#else
- pri_progress(pri->pri, e->ring.call,
- PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
-#endif
- }
- }
- if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) {
- ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
- plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
- } else {
- ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
- if (c)
- ast_hangup(c);
- else {
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
- pri->pvts[chanpos]->call = NULL;
- }
- }
- } else {
- /*
- * Release the PRI lock while we create the channel
- * so other threads can send D channel messages.
- */
- ast_mutex_unlock(&pri->lock);
- c = dahdi_new(pri->pvts[chanpos], AST_STATE_RING, 0, SUB_REAL, law, e->ring.ctype);
- ast_mutex_lock(&pri->lock);
- if (c) {
- /*
- * It is reasonably safe to set the following
- * channel variables while the PRI and DAHDI private
- * structures are locked. The PBX has not been
- * started yet and it is unlikely that any other task
- * will do anything with the channel we have just
- * created.
- */
- if (!ast_strlen_zero(e->ring.callingsubaddr)) {
- pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
- }
- if (e->ring.ani2 >= 0) {
- snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
- pbx_builtin_setvar_helper(c, "ANI2", ani2str);
- pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
- }
-
-#ifdef SUPPORT_USERUSER
- if (!ast_strlen_zero(e->ring.useruserinfo)) {
- pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
- }
-#endif
-
- if (e->ring.redirectingreason >= 0)
- pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
-
- snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
- pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
- }
- if (c && !ast_pbx_start(c)) {
- ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
- plancallingnum, pri->pvts[chanpos]->exten,
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
-
- dahdi_enable_ec(pri->pvts[chanpos]);
- } else {
- ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
- if (c) {
- ast_hangup(c);
- } else {
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
- pri->pvts[chanpos]->call = NULL;
- }
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
+ pri->pvts[chanpos]->call = NULL;
}
}
} else {
- ast_verb(3, "Extension '%s' in context '%s' from '%s' does not exist. Rejecting call on channel %d/%d, span %d\n",
- pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan,
- pri->pvts[chanpos]->prioffset, pri->span);
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
- pri->pvts[chanpos]->call = NULL;
- pri->pvts[chanpos]->exten[0] = '\0';
+ /*
+ * Release the PRI lock while we create the channel so other
+ * threads can send D channel messages. We must also release
+ * the private lock to prevent deadlock while creating the
+ * channel.
+ */
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ ast_mutex_unlock(&pri->lock);
+ c = dahdi_new(pri->pvts[chanpos], AST_STATE_RING, 0, SUB_REAL, law, e->ring.ctype);
+ ast_mutex_lock(&pri->lock);
+ ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ if (c) {
+ /*
+ * It is reasonably safe to set the following
+ * channel variables while the PRI and DAHDI private
+ * structures are locked. The PBX has not been
+ * started yet and it is unlikely that any other task
+ * will do anything with the channel we have just
+ * created.
+ */
+ if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+ pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+ }
+ if (e->ring.ani2 >= 0) {
+ snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
+ pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+ pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
+ }
+
+#ifdef SUPPORT_USERUSER
+ if (!ast_strlen_zero(e->ring.useruserinfo)) {
+ pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
+ }
+#endif
+
+ if (e->ring.redirectingreason >= 0)
+ pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
+
+ snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
+ pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+ }
+ if (c && !ast_pbx_start(c)) {
+ ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
+ plancallingnum, pri->pvts[chanpos]->exten,
+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+
+ dahdi_enable_ec(pri->pvts[chanpos]);
+ } else {
+ ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+ if (c) {
+ /* Avoid deadlock while destroying channel */
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ ast_mutex_unlock(&pri->lock);
+ ast_hangup(c);
+ ast_mutex_lock(&pri->lock);
+ ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ } else {
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
+ pri->pvts[chanpos]->call = NULL;
+ }
+ }
}
- if (crv)
- ast_mutex_unlock(&crv->lock);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
} else {
- if (e->ring.flexible)
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
- else
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
- }
+ ast_verb(3,
+ "Span %d: Extension %s@%s does not exist. Rejecting call from '%s'.\n",
+ pri->span, pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context,
+ pri->pvts[chanpos]->cid_num);
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
+ pri->pvts[chanpos]->call = NULL;
+ pri->pvts[chanpos]->exten[0] = '\0';
+ }
+ if (crv)
+ ast_mutex_unlock(&crv->lock);
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
break;
case PRI_EVENT_RINGING:
chanpos = pri_find_fixup_principle(pri, e->ringing.channel,
@@ -14050,10 +14233,18 @@
}
break;
}
+ } else {
+ /*
+ * Continue hanging up the call even though
+ * we do not have an owner.
+ */
+ pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
+ pri->pvts[chanpos]->call = NULL;
}
ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n",
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
} else {
+ /* Continue hanging up the call. */
pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
pri->pvts[chanpos]->call = NULL;
}
@@ -14133,6 +14324,10 @@
ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
} else {
+ /*
+ * Continue hanging up the call even though
+ * we do not have an owner.
+ */
pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
pri->pvts[chanpos]->call = NULL;
}
More information about the asterisk-commits
mailing list