[asterisk-commits] rmudgett: branch rmudgett/bch_shift_v1.8 r311500 - /team/rmudgett/bch_shift_v...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Mar 22 10:42:41 CDT 2011
Author: rmudgett
Date: Tue Mar 22 10:42:37 2011
New Revision: 311500
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=311500
Log:
Fix deadlock and internal B channel allocation race between in/out going calls.
Modified:
team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c
team/rmudgett/bch_shift_v1.8/channels/sig_pri.c
team/rmudgett/bch_shift_v1.8/channels/sig_pri.h
Modified: team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c?view=diff&rev=311500&r1=311499&r2=311500
==============================================================================
--- team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c (original)
+++ team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c Tue Mar 22 10:42:37 2011
@@ -3221,12 +3221,7 @@
if (pri->pvts[idx] && !pri->pvts[idx]->no_b_channel) {
/* This is a B channel interface. */
++num_b_chans;
- if (pri->pvts[idx]->owner
-#if defined(HAVE_PRI_SERVICE_MESSAGES)
- /* Out-of-service B channels are "in-use". */
- || pri->pvts[idx]->service_status
-#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
- ) {
+ if (!sig_pri_is_chan_available(pri->pvts[idx])) {
++in_use;
}
if (!pri->pvts[idx]->inalarm) {
@@ -13436,18 +13431,23 @@
if (!tmp) {
p->outgoing = 0;
#if defined(HAVE_PRI)
-#if defined(HAVE_PRI_CALL_WAITING)
switch (p->sig) {
case SIG_PRI_LIB_HANDLE_CASES:
+#if defined(HAVE_PRI_CALL_WAITING)
if (((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting) {
((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting = 0;
ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
}
+#endif /* defined(HAVE_PRI_CALL_WAITING) */
+ /*
+ * This should be the last thing to clear when we are done with
+ * the channel.
+ */
+ ((struct sig_pri_chan *) p->sig_pvt)->allocated = 0;
break;
default:
break;
}
-#endif /* defined(HAVE_PRI_CALL_WAITING) */
#endif /* defined(HAVE_PRI) */
} else {
snprintf(p->dialstring, sizeof(p->dialstring), "DAHDI/%s", (char *) data);
Modified: team/rmudgett/bch_shift_v1.8/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bch_shift_v1.8/channels/sig_pri.c?view=diff&rev=311500&r1=311499&r2=311500
==============================================================================
--- team/rmudgett/bch_shift_v1.8/channels/sig_pri.c (original)
+++ team/rmudgett/bch_shift_v1.8/channels/sig_pri.c Tue Mar 22 10:42:37 2011
@@ -1020,6 +1020,38 @@
/*!
* \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 sig_pri_chan *pvt)
+{
+ return pvt->owner || pvt->call || pvt->allocated || pvt->resetting || pvt->inalarm;
+}
+
+/*!
+ * \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.
+ */
+int sig_pri_is_chan_available(struct sig_pri_chan *pvt)
+{
+ return !sig_pri_is_chan_in_use(pvt)
+#if defined(HAVE_PRI_SERVICE_MESSAGES)
+ /* And not out-of-service */
+ && !pvt->service_status
+#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
+ ;
+}
+
+/*!
+ * \internal
* \brief Obtain the sig_pri owner channel lock if the owner exists.
* \since 1.8
*
@@ -1156,6 +1188,7 @@
pri_hangup(pri->pri, call, cause);
pri->pvts[chanpos]->call = NULL;
sig_pri_unlock_private(pri->pvts[chanpos]);
+ sig_pri_span_devstate_changed(pri);
return;
}
pri->pvts[chanpos]->owner->hangupcause = cause;
@@ -1281,7 +1314,7 @@
ast_verb(3, "Moving call (%s) from channel %d to %d.\n",
old_chan->owner ? old_chan->owner->name : "",
old_chan->channel, new_chan->channel);
- if (new_chan->owner) {
+ if (sig_pri_is_chan_available(new_chan)) {
ast_log(LOG_WARNING,
"Can't move call (%s) from channel %d to %d. It is already in use.\n",
old_chan->owner ? old_chan->owner->name : "",
@@ -1312,6 +1345,7 @@
new_chan->alreadyhungup = old_chan->alreadyhungup;
new_chan->isidlecall = old_chan->isidlecall;
new_chan->progress = old_chan->progress;
+ new_chan->allocated = old_chan->allocated;
new_chan->outgoing = old_chan->outgoing;
new_chan->digital = old_chan->digital;
#if defined(HAVE_PRI_CALL_WAITING)
@@ -1326,6 +1360,7 @@
old_chan->alreadyhungup = 0;
old_chan->isidlecall = 0;
old_chan->progress = 0;
+ old_chan->allocated = 0;
old_chan->outgoing = 0;
old_chan->digital = 0;
#if defined(HAVE_PRI_CALL_WAITING)
@@ -1483,39 +1518,49 @@
}
}
-/*! \note Assumes the pri->lock is already obtained. */
-static int pri_check_restart(struct sig_pri_span *pri)
+/*!
+ * \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 sig_pri_span *pri)
{
#if defined(HAVE_PRI_SERVICE_MESSAGES)
-tryanotherpos:
+ unsigned why;
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
- do {
- pri->resetpos++;
- } while (pri->resetpos < pri->numchans
- && (!pri->pvts[pri->resetpos]
+
+ for (++pri->resetpos; pri->resetpos < pri->numchans; ++pri->resetpos) {
+ if (!pri->pvts[pri->resetpos]
|| pri->pvts[pri->resetpos]->no_b_channel
- || pri->pvts[pri->resetpos]->call
- || pri->pvts[pri->resetpos]->resetting));
- if (pri->resetpos < pri->numchans) {
+ || sig_pri_is_chan_in_use(pri->pvts[pri->resetpos])) {
+ continue;
+ }
#if defined(HAVE_PRI_SERVICE_MESSAGES)
- unsigned why;
-
why = pri->pvts[pri->resetpos]->service_status;
if (why) {
- ast_log(LOG_NOTICE, "span '%d' channel '%d' out-of-service (reason: %s), not sending RESTART\n", pri->span,
- pri->pvts[pri->resetpos]->channel, (why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
- goto tryanotherpos;
+ ast_log(LOG_NOTICE,
+ "Span %d: channel %d out-of-service (reason: %s), not sending RESTART\n",
+ pri->span, pri->pvts[pri->resetpos]->channel,
+ (why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
+ continue;
}
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
-
+ break;
+ }
+ if (pri->resetpos < pri->numchans) {
/* Mark the channel as resetting and restart it */
pri->pvts[pri->resetpos]->resetting = 1;
pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
} else {
pri->resetting = 0;
time(&pri->lastreset);
- }
- return 0;
+ sig_pri_span_devstate_changed(pri);
+ }
}
#if defined(HAVE_PRI_CALL_WAITING)
@@ -1550,6 +1595,18 @@
}
#endif /* defined(HAVE_PRI_CALL_WAITING) */
+/*!
+ * \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 sig_pri_span *pri, int backwards)
{
int x;
@@ -1564,8 +1621,7 @@
break;
if (pri->pvts[x]
&& !pri->pvts[x]->no_b_channel
- && !pri->pvts[x]->inalarm
- && !pri->pvts[x]->owner) {
+ && 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;
@@ -1598,8 +1654,7 @@
for (idx = 0; idx < pri->numchans; ++idx) {
if (pri->pvts[idx]
&& pri->pvts[idx]->no_b_channel
- && !pri->pvts[idx]->inalarm
- && !pri->pvts[idx]->owner) {
+ && sig_pri_is_chan_available(pri->pvts[idx])) {
ast_debug(1, "Found empty available no B channel interface\n");
return idx;
}
@@ -1785,6 +1840,9 @@
p->exten[0] = '\0';
/* Since we send release complete here, we won't get one */
p->call = NULL;
+ ast_mutex_lock(&p->pri->lock);
+ sig_pri_span_devstate_changed(p->pri);
+ ast_mutex_unlock(&p->pri->lock);
}
return NULL;
}
@@ -4253,23 +4311,22 @@
return -1;
}
+ chanpos_new = -1;
+
sig_pri_lock_private(pri->pvts[chanpos_old]);
sig_pri_lock_owner(pri, chanpos_old);
owner = pri->pvts[chanpos_old]->owner;
if (!owner) {
- retval = -1;
goto done_with_private;
}
bridged = ast_bridged_channel(owner);
if (!bridged) {
/* Cannot hold a call that is not bridged. */
- retval = -1;
goto done_with_owner;
}
chanpos_new = pri_find_empty_nobch(pri);
if (chanpos_new < 0) {
/* No hold channel available. */
- retval = -1;
goto done_with_owner;
}
sig_pri_handle_subcmds(pri, chanpos_old, ev->e, ev->hold.channel, ev->hold.subcmds,
@@ -4277,7 +4334,6 @@
chanpos_new = pri_fixup_principle(pri, chanpos_new, ev->hold.call);
if (chanpos_new < 0) {
/* Should never happen. */
- retval = -1;
} else {
struct ast_frame f = { AST_FRAME_CONTROL, };
@@ -4287,15 +4343,19 @@
*/
f.subclass.integer = AST_CONTROL_HOLD;
ast_queue_frame(owner, &f);
-
- sig_pri_span_devstate_changed(pri);
- retval = 0;
}
done_with_owner:;
ast_channel_unlock(owner);
done_with_private:;
sig_pri_unlock_private(pri->pvts[chanpos_old]);
+
+ if (chanpos_new < 0) {
+ retval = -1;
+ } else {
+ sig_pri_span_devstate_changed(pri);
+ retval = 0;
+ }
return retval;
}
@@ -4336,10 +4396,10 @@
chanpos = pri_find_principle(pri,
ev->retrieve.channel & ~PRI_HELD_CALL, ev->retrieve.call);
if (ev->retrieve.flexible
- && (chanpos < 0 || pri->pvts[chanpos]->owner || pri->pvts[chanpos]->call)) {
+ && (chanpos < 0 || !sig_pri_is_chan_available(pri->pvts[chanpos]))) {
/*
* Channel selection is flexible and the requested channel
- * is bad or already in use. Pick another channel.
+ * is bad or not available. Pick another channel.
*/
chanpos = pri_find_empty_chan(pri, 1);
}
@@ -4362,9 +4422,9 @@
ev->retrieve.subcmds, ev->retrieve.call);
pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
sig_pri_unlock_private(pri->pvts[chanpos]);
- sig_pri_span_devstate_changed(pri);
pri_retrieve_ack(pri->pri, ev->retrieve.call,
PVT_TO_CHANNEL(pri->pvts[chanpos]));
+ sig_pri_span_devstate_changed(pri);
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
@@ -4430,8 +4490,12 @@
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);
+ if (pri->resetting) {
+ sig_pri_span_devstate_changed(pri);
+ }
+ }
} else {
if (!pri->resetting && (t - pri->lastreset) >= pri->resetinterval) {
pri->resetting = 1;
@@ -4445,32 +4509,41 @@
haveidles = 0;
activeidles = 0;
for (x = pri->numchans; x >= 0; x--) {
- if (pri->pvts[x]
- && !pri->pvts[x]->owner
- && !pri->pvts[x]->call
- && !pri->pvts[x]->no_b_channel) {
- if (haveidles < pri->minunused) {
- haveidles++;
- } else if (!pri->pvts[x]->resetting) {
- nextidle = x;
- break;
+ if (pri->pvts[x] && !pri->pvts[x]->no_b_channel) {
+ 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);
+ pri->pvts[nextidle]->allocated = 1;
+ /*
+ * Release the PRI lock while we create the channel so other
+ * threads can send D channel messages.
+ */
+ ast_mutex_unlock(&pri->lock);
idle = sig_pri_request(pri->pvts[nextidle], AST_FORMAT_ULAW, NULL, 0);
+ ast_mutex_lock(&pri->lock);
if (idle) {
pri->pvts[nextidle]->isidlecall = 1;
if (ast_pthread_create_background(&p, NULL, do_idle_thread, pri->pvts[nextidle])) {
ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
ast_hangup(idle);
}
- } else
+ } else {
+ pri->pvts[nextidle]->allocated = 0;
ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
+ }
gettimeofday(&lastidle, NULL);
}
} else if ((haveidles < pri->minunused) &&
@@ -4682,6 +4755,7 @@
sig_pri_unlock_private(pri->pvts[x]);
}
}
+ sig_pri_span_devstate_changed(pri);
break;
case PRI_EVENT_KEYPAD_DIGIT:
if (sig_pri_is_cis_call(e->digit.channel)) {
@@ -4841,6 +4915,27 @@
} else {
/* A channel is specified. */
chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
+ 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.
@@ -4849,376 +4944,385 @@
#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;
+ }
+
+ sig_pri_lock_private(pri->pvts[chanpos]);
+
+ /* Mark channel as in use so noone else will steal it. */
+ pri->pvts[chanpos]->call = e->ring.call;
+
+ /* Use plancallingnum as a scratch buffer since it is initialized next. */
+ apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri,
+ e->ring.redirectingnum, e->ring.callingplanrdnis);
+ sig_pri_set_rdnis(pri->pvts[chanpos], plancallingnum);
+
+ /* Setup caller-id info */
+ apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
+ pri->pvts[chanpos]->cid_ani2 = 0;
+ 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
+ pri->pvts[chanpos]->cid_subaddr[0] = '\0';
+#if defined(HAVE_PRI_SUBADDR)
+ if (e->ring.calling.subaddress.valid) {
+ struct ast_party_subaddress calling_subaddress;
+
+ ast_party_subaddress_init(&calling_subaddress);
+ sig_pri_set_subaddress(&calling_subaddress,
+ &e->ring.calling.subaddress);
+ if (calling_subaddress.str) {
+ ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
+ calling_subaddress.str,
+ sizeof(pri->pvts[chanpos]->cid_subaddr));
+ }
+ ast_party_subaddress_free(&calling_subaddress);
+ }
+#endif /* defined(HAVE_PRI_SUBADDR) */
+ 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 */
+ pri->pvts[chanpos]->callingpres = e->ring.callingpres;
+ if (e->ring.ani2 >= 0) {
+ pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
+ }
} else {
- sig_pri_lock_private(pri->pvts[chanpos]);
- 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);
- sig_pri_unlock_private(pri->pvts[chanpos]);
+ pri->pvts[chanpos]->cid_num[0] = '\0';
+ pri->pvts[chanpos]->cid_subaddr[0] = '\0';
+ pri->pvts[chanpos]->cid_ani[0] = '\0';
+ pri->pvts[chanpos]->cid_name[0] = '\0';
+ pri->pvts[chanpos]->cid_ton = 0;
+ pri->pvts[chanpos]->callingpres = 0;
+ }
+
+ /* Setup the user tag for party id's from this device for this call. */
+ if (pri->append_msn_to_user_tag) {
+ snprintf(pri->pvts[chanpos]->user_tag,
+ sizeof(pri->pvts[chanpos]->user_tag), "%s_%s",
+ pri->initial_user_tag,
+ pri->nodetype == PRI_NETWORK
+ ? plancallingnum : e->ring.callednum);
+ } else {
+ ast_copy_string(pri->pvts[chanpos]->user_tag,
+ pri->initial_user_tag, sizeof(pri->pvts[chanpos]->user_tag));
+ }
+
+ sig_pri_set_caller_id(pri->pvts[chanpos]);
+
+ /* Set DNID on all incoming calls -- even immediate */
+ sig_pri_set_dnid(pri->pvts[chanpos], e->ring.callednum);
+
+ /* 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 */
+ if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
+ /* Just announce proceeding */
+ pri->pvts[chanpos]->call_level = SIG_PRI_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 = SIG_PRI_CALL_LEVEL_CONNECT;
+ pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+ } else {
+ pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
+ pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+ }
+
+ /* 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.
+ */
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+ ast_mutex_unlock(&pri->lock);
+ c = sig_pri_new_ast_channel(pri->pvts[chanpos],
+ AST_STATE_RESERVED,
+ (e->ring.layer1 == PRI_LAYER_1_ALAW)
+ ? SIG_PRI_ALAW : SIG_PRI_ULAW,
+ e->ring.ctype, pri->pvts[chanpos]->exten, NULL);
+ ast_mutex_lock(&pri->lock);
+ sig_pri_lock_private(pri->pvts[chanpos]);
+ if (c) {
+#if defined(HAVE_PRI_SUBADDR)
+ if (e->ring.calling.subaddress.valid) {
+ /* Set Calling Subaddress */
+ sig_pri_lock_owner(pri, chanpos);
+ sig_pri_set_subaddress(
+ &pri->pvts[chanpos]->owner->caller.id.subaddress,
+ &e->ring.calling.subaddress);
+ if (!e->ring.calling.subaddress.type
+ && !ast_strlen_zero(
+ (char *) e->ring.calling.subaddress.data)) {
+ /* NSAP */
+ pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
+ (char *) e->ring.calling.subaddress.data);
+ }
+ ast_channel_unlock(c);
+ }
+ if (e->ring.called_subaddress.valid) {
+ /* Set Called Subaddress */
+ sig_pri_lock_owner(pri, chanpos);
+ sig_pri_set_subaddress(
+ &pri->pvts[chanpos]->owner->dialed.subaddress,
+ &e->ring.called_subaddress);
+ if (!e->ring.called_subaddress.type
+ && !ast_strlen_zero(
+ (char *) e->ring.called_subaddress.data)) {
+ /* NSAP */
+ pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
+ (char *) e->ring.called_subaddress.data);
+ }
+ ast_channel_unlock(c);
+ }
+#else
+ if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+ pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+ }
+#endif /* !defined(HAVE_PRI_SUBADDR) */
+ if (e->ring.ani2 >= 0) {
+ snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
+ pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+ }
+
+#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) {
+ /* This is now just a status variable. Use REDIRECTING() dialplan function. */
+ pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
+ }
+#if defined(HAVE_PRI_REVERSE_CHARGE)
+ pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
+#endif
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+ ast_copy_string(pri->pvts[chanpos]->keypad_digits,
+ e->ring.keypad_digits,
+ sizeof(pri->pvts[chanpos]->keypad_digits));
+#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
+
+ sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
+ e->ring.subcmds, e->ring.call);
+
+ if (!pri->pvts[chanpos]->digital
+ && !pri->pvts[chanpos]->no_b_channel) {
+ /*
+ * 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, pri_ss_thread, pri->pvts[chanpos])) {
+ 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) {
+ /* Avoid deadlock while destroying channel */
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+ ast_mutex_unlock(&pri->lock);
+ ast_hangup(c);
+ ast_mutex_lock(&pri->lock);
+ } else {
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
+ pri->pvts[chanpos]->call = NULL;
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+ sig_pri_span_devstate_changed(pri);
+ }
break;
+ }
+ } else {
+ /*
+ * 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.
+ */
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+ ast_mutex_unlock(&pri->lock);
+ c = sig_pri_new_ast_channel(pri->pvts[chanpos],
+ AST_STATE_RING,
+ (e->ring.layer1 == PRI_LAYER_1_ALAW)
+ ? SIG_PRI_ALAW : SIG_PRI_ULAW, e->ring.ctype,
+ pri->pvts[chanpos]->exten, NULL);
+ ast_mutex_lock(&pri->lock);
+ sig_pri_lock_private(pri->pvts[chanpos]);
+ 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 defined(HAVE_PRI_SUBADDR)
+ if (e->ring.calling.subaddress.valid) {
+ /* Set Calling Subaddress */
+ sig_pri_lock_owner(pri, chanpos);
+ sig_pri_set_subaddress(
+ &pri->pvts[chanpos]->owner->caller.id.subaddress,
+ &e->ring.calling.subaddress);
+ if (!e->ring.calling.subaddress.type
+ && !ast_strlen_zero(
+ (char *) e->ring.calling.subaddress.data)) {
+ /* NSAP */
+ pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
+ (char *) e->ring.calling.subaddress.data);
+ }
+ ast_channel_unlock(c);
+ }
+ if (e->ring.called_subaddress.valid) {
+ /* Set Called Subaddress */
+ sig_pri_lock_owner(pri, chanpos);
+ sig_pri_set_subaddress(
+ &pri->pvts[chanpos]->owner->dialed.subaddress,
+ &e->ring.called_subaddress);
+ if (!e->ring.called_subaddress.type
+ && !ast_strlen_zero(
+ (char *) e->ring.called_subaddress.data)) {
+ /* NSAP */
+ pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
+ (char *) e->ring.called_subaddress.data);
+ }
+ ast_channel_unlock(c);
+ }
+#else
+ if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+ pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+ }
+#endif /* !defined(HAVE_PRI_SUBADDR) */
+ if (e->ring.ani2 >= 0) {
+ snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
+ pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+ }
+
+#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) {
+ /* This is now just a status variable. Use REDIRECTING() dialplan function. */
+ pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
+ }
+#if defined(HAVE_PRI_REVERSE_CHARGE)
+ pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
+#endif
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+ ast_copy_string(pri->pvts[chanpos]->keypad_digits,
+ e->ring.keypad_digits,
+ sizeof(pri->pvts[chanpos]->keypad_digits));
+#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
+
+ snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
+ pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+
+ sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
+ e->ring.subcmds, e->ring.call);
+
+ }
+ 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);
+ sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
} 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 renegotiating channel.\n",
- PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
- sig_pri_unlock_private(pri->pvts[chanpos]);
- chanpos = -1;
+ 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 */
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+ ast_mutex_unlock(&pri->lock);
+ ast_hangup(c);
+ ast_mutex_lock(&pri->lock);
+ } else {
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
+ pri->pvts[chanpos]->call = NULL;
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+ sig_pri_span_devstate_changed(pri);
+ }
+ break;
}
}
- if (chanpos > -1)
- sig_pri_unlock_private(pri->pvts[chanpos]);
- }
- if ((chanpos < 0) && (e->ring.flexible))
- chanpos = pri_find_empty_chan(pri, 1);
- if (chanpos > -1) {
- sig_pri_lock_private(pri->pvts[chanpos]);
- pri->pvts[chanpos]->call = e->ring.call;
-
- /* Use plancallingnum as a scratch buffer since it is initialized next. */
- apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri,
- e->ring.redirectingnum, e->ring.callingplanrdnis);
- sig_pri_set_rdnis(pri->pvts[chanpos], plancallingnum);
-
- /* Setup caller-id info */
- apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
- pri->pvts[chanpos]->cid_ani2 = 0;
- 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
- pri->pvts[chanpos]->cid_subaddr[0] = '\0';
-#if defined(HAVE_PRI_SUBADDR)
- if (e->ring.calling.subaddress.valid) {
- struct ast_party_subaddress calling_subaddress;
-
- ast_party_subaddress_init(&calling_subaddress);
- sig_pri_set_subaddress(&calling_subaddress,
- &e->ring.calling.subaddress);
- if (calling_subaddress.str) {
- ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
- calling_subaddress.str,
- sizeof(pri->pvts[chanpos]->cid_subaddr));
- }
- ast_party_subaddress_free(&calling_subaddress);
- }
-#endif /* defined(HAVE_PRI_SUBADDR) */
- 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 */
- pri->pvts[chanpos]->callingpres = e->ring.callingpres;
- if (e->ring.ani2 >= 0) {
- pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
- }
- } else {
- pri->pvts[chanpos]->cid_num[0] = '\0';
- pri->pvts[chanpos]->cid_subaddr[0] = '\0';
- pri->pvts[chanpos]->cid_ani[0] = '\0';
- pri->pvts[chanpos]->cid_name[0] = '\0';
- pri->pvts[chanpos]->cid_ton = 0;
- pri->pvts[chanpos]->callingpres = 0;
- }
-
- /* Setup the user tag for party id's from this device for this call. */
- if (pri->append_msn_to_user_tag) {
- snprintf(pri->pvts[chanpos]->user_tag,
- sizeof(pri->pvts[chanpos]->user_tag), "%s_%s",
- pri->initial_user_tag,
- pri->nodetype == PRI_NETWORK
- ? plancallingnum : e->ring.callednum);
- } else {
- ast_copy_string(pri->pvts[chanpos]->user_tag,
- pri->initial_user_tag, sizeof(pri->pvts[chanpos]->user_tag));
- }
-
- sig_pri_set_caller_id(pri->pvts[chanpos]);
-
- /* Set DNID on all incoming calls -- even immediate */
- sig_pri_set_dnid(pri->pvts[chanpos], e->ring.callednum);
-
- /* 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 */
- if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
- /* Just announce proceeding */
- pri->pvts[chanpos]->call_level = SIG_PRI_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 = SIG_PRI_CALL_LEVEL_CONNECT;
- pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
- } else {
- pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
- pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
- }
-
- /* 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);
- c = sig_pri_new_ast_channel(pri->pvts[chanpos],
- AST_STATE_RESERVED,
- (e->ring.layer1 == PRI_LAYER_1_ALAW)
- ? SIG_PRI_ALAW : SIG_PRI_ULAW,
- e->ring.ctype, pri->pvts[chanpos]->exten, NULL);
- ast_mutex_lock(&pri->lock);
- if (c) {
-#if defined(HAVE_PRI_SUBADDR)
- if (e->ring.calling.subaddress.valid) {
- /* Set Calling Subaddress */
- sig_pri_lock_owner(pri, chanpos);
- sig_pri_set_subaddress(
- &pri->pvts[chanpos]->owner->caller.id.subaddress,
- &e->ring.calling.subaddress);
- if (!e->ring.calling.subaddress.type
- && !ast_strlen_zero(
- (char *) e->ring.calling.subaddress.data)) {
- /* NSAP */
- pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
- (char *) e->ring.calling.subaddress.data);
- }
- ast_channel_unlock(c);
- }
- if (e->ring.called_subaddress.valid) {
- /* Set Called Subaddress */
- sig_pri_lock_owner(pri, chanpos);
- sig_pri_set_subaddress(
- &pri->pvts[chanpos]->owner->dialed.subaddress,
- &e->ring.called_subaddress);
- if (!e->ring.called_subaddress.type
- && !ast_strlen_zero(
- (char *) e->ring.called_subaddress.data)) {
- /* NSAP */
- pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
- (char *) e->ring.called_subaddress.data);
- }
- ast_channel_unlock(c);
- }
-#else
- if (!ast_strlen_zero(e->ring.callingsubaddr)) {
- pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
- }
-#endif /* !defined(HAVE_PRI_SUBADDR) */
- if (e->ring.ani2 >= 0) {
- snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
- pbx_builtin_setvar_helper(c, "ANI2", ani2str);
- }
-
-#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) {
- /* This is now just a status variable. Use REDIRECTING() dialplan function. */
- pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
- }
-#if defined(HAVE_PRI_REVERSE_CHARGE)
- pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
-#endif
-#if defined(HAVE_PRI_SETUP_KEYPAD)
- ast_copy_string(pri->pvts[chanpos]->keypad_digits,
- e->ring.keypad_digits,
- sizeof(pri->pvts[chanpos]->keypad_digits));
-#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
-
- sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
- e->ring.subcmds, e->ring.call);
-
- if (!pri->pvts[chanpos]->digital
- && !pri->pvts[chanpos]->no_b_channel) {
- /*
- * 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
[... 363 lines stripped ...]
More information about the asterisk-commits
mailing list