[asterisk-commits] rmudgett: branch rmudgett/bch_shift_trunk r311680 - in /team/rmudgett/bch_shi...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Mar 25 11:51:19 CDT 2011
Author: rmudgett
Date: Fri Mar 25 11:51:15 2011
New Revision: 311680
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=311680
Log:
Merged revisions 311500,311556-311557,311604,311607-311608,311610,311664-311665,311672,311674,311676 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.
........
r311556 | rmudgett | 2011-03-22 17:52:16 -0500 (Tue, 22 Mar 2011) | 1 line
Mostly restart message format changes.
........
r311557 | rmudgett | 2011-03-22 17:58:26 -0500 (Tue, 22 Mar 2011) | 1 line
Add allocated flag to 'dahdi show channel' PRI output.
........
r311604 | rmudgett | 2011-03-23 09:40:26 -0500 (Wed, 23 Mar 2011) | 1 line
Block SETUPs with duplicate call ptr.
........
r311607 | rmudgett | 2011-03-23 11:39:27 -0500 (Wed, 23 Mar 2011) | 1 line
Add conditional code around force restart code.
........
r311608 | rmudgett | 2011-03-23 12:15:03 -0500 (Wed, 23 Mar 2011) | 1 line
Invert test logic. It will work better now.
........
r311610 | rmudgett | 2011-03-23 15:10:31 -0500 (Wed, 23 Mar 2011) | 1 line
Make RESTART request not destroy call and update hangup/restart verbose messages.
........
r311664 | rmudgett | 2011-03-24 13:35:05 -0500 (Thu, 24 Mar 2011) | 2 lines
Just destroy calls if T309 is not enabled.
........
r311665 | rmudgett | 2011-03-24 14:41:56 -0500 (Thu, 24 Mar 2011) | 30 lines
Invalid PRI call ptr message associated with force channel RESTART.
When Asterisk receives a cause PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44), it
forces a RESTART on that B channel. Due to timing, another SETUP
requesting the same B channel could come in right after the
RELEASE_COMPLETE with cause 44. That call SETUP would get shifted to
another channel and two messages sent immediately (SETUP_ACKNOWLEDGE,
PROCEEDING, ALERTING, or CONNECT). The peer Asterisk box on receiving the
RESTART, immediately hangs up and destroys the new call associated with the B channel.
When the peer then processes the two messages for the destroyed call, it
responds with PRI_CAUSE_INVALID_CALL_REFERENCE(81) to both.
--> SETUP(call-1)
<-- RELEASE_COMPLETE(call-1, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL)
<-- SETUP(call-2, same B channel)
--> RESTART
--> SETUP_ACKNOWLEDGE(call-2, New B channel)
--> CONNECT(call-2)
<-- RESTART_ACKNOWLEDGE (Destroys call-2 because associated with B channel)
<-- RELEASE_COMPLETE(call-2, PRI_CAUSE_INVALID_CALL_REFERENCE)
<-- RELEASE_COMPLETE(call-2, PRI_CAUSE_INVALID_CALL_REFERENCE)
If both RELEASE_COMPLETE responses are processed by libpri before the
Asterisk core hangs up the call, then the invalid call ptr message is
generated. Libpri has already destroyed the call structure when it
processed the second RELEASE_COMPLETE.
Fixed by making sure that the call is hung up and forgotten immediately if
the hangup cause is PRI_CAUSE_INVALID_CALL_REFERENCE.
........
r311672 | rmudgett | 2011-03-24 16:48:42 -0500 (Thu, 24 Mar 2011) | 7 lines
Don't continue to deal with the B channel after we have effectively released it.
In sig_pri_hangup(), the owner ptr and allocated flag should not be
cleared outside of the PRI lock protection. Also they should be cleared
as the last steps in hangup since they release the B channel for other
calls to use.
........
r311674 | rmudgett | 2011-03-24 18:02:23 -0500 (Thu, 24 Mar 2011) | 1 line
Make sure that the last call has completed hanging up before setting up for the new.
........
r311676 | rmudgett | 2011-03-25 09:47:44 -0500 (Fri, 25 Mar 2011) | 1 line
Update comment since I fixed the problem it mentions.
........
Modified:
team/rmudgett/bch_shift_trunk/ (props changed)
team/rmudgett/bch_shift_trunk/channels/chan_dahdi.c
team/rmudgett/bch_shift_trunk/channels/sig_pri.c
team/rmudgett/bch_shift_trunk/channels/sig_pri.h
Propchange: team/rmudgett/bch_shift_trunk/
------------------------------------------------------------------------------
--- bch_shift_v1.8-integrated (original)
+++ bch_shift_v1.8-integrated Fri Mar 25 11:51:15 2011
@@ -1,1 +1,1 @@
-/team/rmudgett/bch_shift_v1.8:1-311499
+/team/rmudgett/bch_shift_v1.8:1-311678
Modified: team/rmudgett/bch_shift_trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bch_shift_trunk/channels/chan_dahdi.c?view=diff&rev=311680&r1=311679&r2=311680
==============================================================================
--- team/rmudgett/bch_shift_trunk/channels/chan_dahdi.c (original)
+++ team/rmudgett/bch_shift_trunk/channels/chan_dahdi.c Fri Mar 25 11:51:15 2011
@@ -3243,12 +3243,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) {
@@ -6463,11 +6458,9 @@
p->cidspill = NULL;
ast_mutex_unlock(&p->lock);
- ast_module_unref(ast_module_info->self);
ast_verb(3, "Hungup '%s'\n", ast->name);
ast_mutex_lock(&iflock);
-
if (p->restartpending) {
num_restart_pending--;
}
@@ -6476,6 +6469,8 @@
destroy_channel(p, 0);
}
ast_mutex_unlock(&iflock);
+
+ ast_module_unref(ast_module_info->self);
return 0;
}
@@ -13508,6 +13503,14 @@
tmp = analog_request(p->sig_pvt, &callwait, requestor);
#ifdef HAVE_PRI
} else if (dahdi_sig_pri_lib_handles(p->sig)) {
+ /*
+ * We already have the B channel reserved for this call. We
+ * just need to make sure that dahdi_hangup() has completed
+ * cleaning up before continuing.
+ */
+ ast_mutex_lock(&p->lock);
+ ast_mutex_unlock(&p->lock);
+
sig_pri_extract_called_num_subaddr(p->sig_pvt, data, p->dnid,
sizeof(p->dnid));
tmp = sig_pri_request(p->sig_pvt, SIG_PRI_DEFLAW, requestor, transcapdigital);
@@ -13522,18 +13525,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);
@@ -15213,6 +15221,9 @@
ast_cli(a->fd, "Resetting ");
if (chan->call)
ast_cli(a->fd, "Call ");
+ if (chan->allocated) {
+ ast_cli(a->fd, "Allocated ");
+ }
ast_cli(a->fd, "\n");
if (tmp->logicalspan)
ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
Modified: team/rmudgett/bch_shift_trunk/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bch_shift_trunk/channels/sig_pri.c?view=diff&rev=311680&r1=311679&r2=311680
==============================================================================
--- team/rmudgett/bch_shift_trunk/channels/sig_pri.c (original)
+++ team/rmudgett/bch_shift_trunk/channels/sig_pri.c Fri Mar 25 11:51:15 2011
@@ -55,6 +55,22 @@
/* define this to send PRI user-user information elements */
#undef SUPPORT_USERUSER
+
+/*!
+ * Define to make always pick a channel if allowed. Useful for
+ * testing channel shifting.
+ */
+//#define ALWAYS_PICK_CHANNEL 1
+#define ALWAYS_PICK_CHANNEL 1 //BUGBUG
+
+/*!
+ * Define to force a RESTART on a channel that returns a cause
+ * code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44). If the cause
+ * is because of a stuck channel on the peer and the channel is
+ * always the next channel we pick for an outgoing call then
+ * this can help.
+ */
+#define FORCE_RESTART_UNAVAIL_CHANS 1
#if defined(HAVE_PRI_CCSS)
struct sig_pri_cc_agent_prv {
@@ -1039,6 +1055,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
*
@@ -1175,6 +1223,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;
@@ -1289,7 +1338,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 : "",
@@ -1320,6 +1369,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)
@@ -1334,6 +1384,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)
@@ -1495,39 +1546,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)
@@ -1562,6 +1623,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;
@@ -1576,8 +1649,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;
@@ -1610,8 +1682,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;
}
@@ -1797,6 +1868,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;
}
@@ -4953,23 +5027,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,
@@ -4979,17 +5052,21 @@
if (chanpos_new < 0) {
/* Should never happen. */
pri_queue_control(pri, chanpos_old, AST_CONTROL_UNHOLD);
- retval = -1;
} else {
sig_pri_ami_hold_event(owner, 1);
- 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;
}
@@ -5038,6 +5115,7 @@
sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
SIG_PRI_MOH_EVENT_HOLD_ACK);
sig_pri_unlock_private(pri->pvts[chanpos]);
+ sig_pri_span_devstate_changed(pri);
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
@@ -5119,10 +5197,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);
}
@@ -5187,6 +5265,7 @@
sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
SIG_PRI_MOH_EVENT_RETRIEVE_ACK);
sig_pri_unlock_private(pri->pvts[chanpos]);
+ sig_pri_span_devstate_changed(pri);
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
@@ -5295,8 +5374,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;
@@ -5310,32 +5393,48 @@
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);
+ /*
+ * We already have the B channel reserved for this call. We
+ * just need to make sure that sig_pri_hangup() has completed
+ * cleaning up before continuing.
+ */
+ sig_pri_lock_private(pri->pvts[nextidle]);
+ sig_pri_unlock_private(pri->pvts[nextidle]);
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) &&
@@ -5481,10 +5580,9 @@
struct sig_pri_chan *p = pri->pvts[i];
if (p) {
if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
- /* T309 is not enabled : hangup calls when alarm occurs */
+ /* T309 is not enabled : destroy calls when alarm occurs */
if (p->call) {
if (p->pri && p->pri->pri) {
- pri_hangup(p->pri->pri, p->call, -1);
pri_destroycall(p->pri->pri, p->call);
p->call = NULL;
} else
@@ -5500,11 +5598,13 @@
}
break;
case PRI_EVENT_RESTART:
- if (e->restart.channel > -1) {
+ if (e->restart.channel > -1 && PRI_CHANNEL(e->ring.channel) != 0xFF) {
chanpos = pri_find_principle(pri, e->restart.channel, NULL);
if (chanpos < 0)
- ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n",
- PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
+ ast_log(LOG_WARNING,
+ "Span %d: Restart requested on odd/unavailable channel number %d/%d\n",
+ pri->span, PRI_SPAN(e->restart.channel),
+ PRI_CHANNEL(e->restart.channel));
else {
int skipit = 0;
#if defined(HAVE_PRI_SERVICE_MESSAGES)
@@ -5513,16 +5613,18 @@
why = pri->pvts[chanpos]->service_status;
if (why) {
ast_log(LOG_NOTICE,
- "span '%d' channel '%d' out-of-service (reason: %s), ignoring RESTART\n",
- pri->span, PRI_CHANNEL(e->restart.channel),
+ "Span %d: Channel %d/%d out-of-service (reason: %s), ignoring RESTART\n",
+ pri->span, PRI_SPAN(e->restart.channel),
+ PRI_CHANNEL(e->restart.channel),
(why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
skipit = 1;
}
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
sig_pri_lock_private(pri->pvts[chanpos]);
if (!skipit) {
- ast_verb(3, "B-channel %d/%d restarted on span %d\n",
- PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
+ ast_verb(3, "Span %d: Channel %d/%d restarted\n", pri->span,
+ PRI_SPAN(e->restart.channel),
+ PRI_CHANNEL(e->restart.channel));
if (pri->pvts[chanpos]->call) {
pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
pri->pvts[chanpos]->call = NULL;
@@ -5547,6 +5649,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)) {
@@ -5680,6 +5783,15 @@
e->ring.call);
break;
}
+ chanpos = pri_find_principle_by_call(pri, e->ring.call);
+ if (-1 < chanpos) {
+ /* Libpri has already filtered out duplicate SETUPs. */
+ ast_log(LOG_WARNING,
+ "Span %d: Got SETUP with duplicate call ptr. Dropping call.\n",
+ pri->span);
+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_TEMPORARY_FAILURE);
+ break;
+ }
if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF) {
/* Any channel requested. */
chanpos = pri_find_empty_chan(pri, 1);
@@ -5706,384 +5818,400 @@
} else {
/* A channel is specified. */
chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
-/*!
- * Define to make always pick a channel if allowed. Useful for
- * testing channel shifting.
- */
-//#define ALWAYS_PICK_CHANNEL 1
-#define ALWAYS_PICK_CHANNEL 1 //BUGBUG
+ 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])) {
+ /* 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;
+ }
#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. */
[... 861 lines stripped ...]
More information about the asterisk-commits
mailing list