[asterisk-commits] qwell: tag 1.8.9.1 r354210 - in /tags/1.8.9.1: ./ channels/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Feb 6 15:40:42 CST 2012
Author: qwell
Date: Mon Feb 6 15:40:37 2012
New Revision: 354210
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=354210
Log:
Update .version and ChangeLog. Merge fixes.
Modified:
tags/1.8.9.1/.version
tags/1.8.9.1/ChangeLog
tags/1.8.9.1/channels/chan_agent.c
tags/1.8.9.1/channels/chan_sip.c
Modified: tags/1.8.9.1/.version
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.9.1/.version?view=diff&rev=354210&r1=354209&r2=354210
==============================================================================
--- tags/1.8.9.1/.version (original)
+++ tags/1.8.9.1/.version Mon Feb 6 15:40:37 2012
@@ -1,1 +1,1 @@
-1.8.9.0
+1.8.9.1
Modified: tags/1.8.9.1/ChangeLog
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.9.1/ChangeLog?view=diff&rev=354210&r1=354209&r2=354210
==============================================================================
--- tags/1.8.9.1/ChangeLog (original)
+++ tags/1.8.9.1/ChangeLog Mon Feb 6 15:40:37 2012
@@ -1,3 +1,25 @@
+2012-02-06 Asterisk Development Team <asteriskteam at digium.com>
+
+ * Asterisk 1.8.9.1 Released.
+
+ * channels/chan_agent.c: Fixes deadlocks occuring in chan_agent due to
+ r335976. Bad locking order was added to chan_agent to prevent
+ segfaults from having no locking in a patch by irroot. This patch
+ addresses the bad locking order by releasing locks before getting the
+ right locking order to stop deadlocks from occuring when doing
+ multiple interactions with agents. (closes issue ASTERISK-19285)
+ Reported by: Alex Villacis Lasso
+ Review: https://reviewboard.asterisk.org/r/1708/
+
+ * channels/chan_sip.c: Ensure entering T.38 passthrough does not cause
+ an infinite loop. After R340970 Asterisk was still polling the RTCP
+ file descriptor after RTCP is shut down and removed. If the
+ descriptor happened to have data ready when the removal occured then
+ Asterisk would go into an infinite loop trying to read data that it
+ can never actually access. This change disables the audio RTCP file
+ descriptor for the duration of the T.38 transaction. (closes issue
+ ASTERISK-18951) Reported-by: Kristijan Vrban
+
2012-01-27 Asterisk Development Team <asteriskteam at digium.com>
* Asterisk 1.8.9.0 Released.
Modified: tags/1.8.9.1/channels/chan_agent.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.9.1/channels/chan_agent.c?view=diff&rev=354210&r1=354209&r2=354210
==============================================================================
--- tags/1.8.9.1/channels/chan_agent.c (original)
+++ tags/1.8.9.1/channels/chan_agent.c Mon Feb 6 15:40:37 2012
@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 1999 - 2006, Digium, Inc.
+ * Copyright (C) 1999 - 2012, Digium, Inc.
*
* Mark Spencer <markster at digium.com>
*
@@ -375,6 +375,43 @@
};
/*!
+ * \brief Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt
+ * must enter this function locked and will be returned locked, but this function will
+ * unlock the pvt for a short time, so it can't be used while expecting the pvt to remain
+ * static. If function returns a non NULL channel, it will need to be unlocked and
+ * unrefed once it is no longer needed.
+ *
+ * \param pvt Pointer to the LOCKED agent_pvt for which the owner is needed
+ * \ret locked channel which owns the pvt at the time of completion. NULL if not available.
+ */
+static struct ast_channel *agent_lock_owner(struct agent_pvt *pvt)
+{
+ struct ast_channel *owner;
+
+ for (;;) {
+ if (!pvt->owner) { /* No owner. Nothing to do. */
+ return NULL;
+ }
+
+ /* If we don't ref the owner, it could be killed when we unlock the pvt. */
+ owner = ast_channel_ref(pvt->owner);
+
+ /* Locking order requires us to lock channel, then pvt. */
+ ast_mutex_unlock(&pvt->lock);
+ ast_channel_lock(owner);
+ ast_mutex_lock(&pvt->lock);
+
+ /* Check if owner changed during pvt unlock period */
+ if (owner != pvt->owner) { /* Channel changed. Unref and do another pass. */
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ } else { /* Channel stayed the same. Return it. */
+ return owner;
+ }
+ }
+}
+
+/*!
* Adds an agent to the global list of agents.
*
* \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
@@ -554,7 +591,11 @@
struct ast_frame *f = NULL;
static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
int cur_time = time(NULL);
+ struct ast_channel *owner;
+
ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
+
CHECK_FORMATS(ast, p);
if (!p->start) {
p->start = cur_time;
@@ -584,13 +625,11 @@
int howlong = cur_time - p->start;
if (p->autologoff && (howlong >= p->autologoff)) {
ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
- if (p->owner || p->chan) {
- while (p->owner && ast_channel_trylock(p->owner)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- }
- if (p->owner) {
- ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
- ast_channel_unlock(p->owner);
+ if (owner || p->chan) {
+ if (owner) {
+ ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
}
while (p->chan && ast_channel_trylock(p->chan)) {
@@ -652,6 +691,11 @@
}
}
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
+
CLEANUP(ast,p);
if (p->chan && !p->chan->_bridge) {
if (strcasecmp(p->chan->tech->type, "Local")) {
@@ -887,6 +931,14 @@
static int agent_hangup(struct ast_channel *ast)
{
struct agent_pvt *p = ast->tech_pvt;
+ struct ast_channel *indicate_chan = NULL;
+ char *tmp_moh; /* moh buffer for indicating after unlocking p */
+
+ if (p->pending) {
+ AST_LIST_LOCK(&agents);
+ AST_LIST_REMOVE(&agents, p, list);
+ AST_LIST_UNLOCK(&agents);
+ }
ast_mutex_lock(&p->lock);
p->owner = NULL;
@@ -909,7 +961,7 @@
if (p->start && (ast->_state != AST_STATE_UP)) {
p->start = 0;
} else
- p->start = 0;
+ p->start = 0;
if (p->chan) {
p->chan->_bridge = NULL;
/* If they're dead, go ahead and hang up on the agent now */
@@ -918,14 +970,20 @@
ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
ast_channel_unlock(p->chan);
} else if (p->loginstart) {
- ast_channel_lock(p->chan);
- ast_indicate_data(p->chan, AST_CONTROL_HOLD,
- S_OR(p->moh, NULL),
- !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
- ast_channel_unlock(p->chan);
+ indicate_chan = ast_channel_ref(p->chan);
+ tmp_moh = ast_strdupa(p->moh);
}
}
ast_mutex_unlock(&p->lock);
+
+ if (indicate_chan) {
+ ast_channel_lock(indicate_chan);
+ ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
+ S_OR(tmp_moh, NULL),
+ !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0);
+ ast_channel_unlock(indicate_chan);
+ indicate_chan = ast_channel_unref(indicate_chan);
+ }
/* Only register a device state change if the agent is still logged in */
if (!p->loginstart) {
@@ -934,11 +992,6 @@
ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
}
- if (p->pending) {
- AST_LIST_LOCK(&agents);
- AST_LIST_REMOVE(&agents, p, list);
- AST_LIST_UNLOCK(&agents);
- }
if (p->abouttograb) {
/* Let the "about to grab" thread know this isn't valid anymore, and let it
kill it later */
@@ -1491,6 +1544,8 @@
/*!
* Lists agents and their status to the Manager API.
* It is registered on load_module() and it gets called by the manager backend.
+ * This function locks both the pvt and the channel that owns it for a while, but
+ * does not keep these locks.
* \param s
* \param m
* \returns
@@ -1513,7 +1568,9 @@
astman_send_ack(s, m, "Agents will follow");
AST_LIST_LOCK(&agents);
AST_LIST_TRAVERSE(&agents, p, list) {
- ast_mutex_lock(&p->lock);
+ struct ast_channel *owner;
+ ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
/* Status Values:
AGENT_LOGGEDOFF - Agent isn't logged in
@@ -1528,16 +1585,14 @@
if (p->chan) {
loginChan = ast_strdupa(p->chan->name);
- if (p->owner && p->owner->_bridge) {
+ if (owner && owner->_bridge) {
talkingto = S_COR(p->chan->caller.id.number.valid,
p->chan->caller.id.number.str, "n/a");
- ast_channel_lock(p->owner);
- if ((bridge = ast_bridged_channel(p->owner))) {
+ if ((bridge = ast_bridged_channel(owner))) {
talkingtoChan = ast_strdupa(bridge->name);
} else {
talkingtoChan = "n/a";
}
- ast_channel_unlock(p->owner);
status = "AGENT_ONCALL";
} else {
talkingto = "n/a";
@@ -1549,6 +1604,11 @@
talkingto = "n/a";
talkingtoChan = "n/a";
status = "AGENT_LOGGEDOFF";
+ }
+
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
}
astman_append(s, "Event: Agents\r\n"
@@ -1582,14 +1642,14 @@
ret = 0;
if (p->owner || p->chan) {
if (!soft) {
+ struct ast_channel *owner;
ast_mutex_lock(&p->lock);
-
- while (p->owner && ast_channel_trylock(p->owner)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- }
- if (p->owner) {
- ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
- ast_channel_unlock(p->owner);
+ owner = agent_lock_owner(p);
+
+ if (owner) {
+ ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
}
while (p->chan && ast_channel_trylock(p->chan)) {
@@ -1726,7 +1786,9 @@
AST_LIST_LOCK(&agents);
AST_LIST_TRAVERSE(&agents, p, list) {
+ struct ast_channel *owner;
ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
if (p->pending) {
if (p->group)
ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
@@ -1739,10 +1801,11 @@
username[0] = '\0';
if (p->chan) {
snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
- if (p->owner && ast_bridged_channel(p->owner))
+ if (owner && ast_bridged_channel(owner)) {
snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
- else
+ } else {
strcpy(talkingto, " is idle");
+ }
online_agents++;
} else {
strcpy(location, "not logged in");
@@ -1755,6 +1818,11 @@
username, location, talkingto, music);
count_agents++;
}
+
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
ast_mutex_unlock(&p->lock);
}
AST_LIST_UNLOCK(&agents);
@@ -1795,21 +1863,32 @@
AST_LIST_LOCK(&agents);
AST_LIST_TRAVERSE(&agents, p, list) {
+ struct ast_channel *owner;
+
agent_status = 0; /* reset it to offline */
ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
+
if (!ast_strlen_zero(p->name))
snprintf(username, sizeof(username), "(%s) ", p->name);
else
username[0] = '\0';
if (p->chan) {
snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
- if (p->owner && ast_bridged_channel(p->owner))
- snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
- else
+ if (owner && ast_bridged_channel(owner)) {
+ snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(owner)->name);
+ } else {
strcpy(talkingto, " is idle");
+ }
agent_status = 1;
online_agents++;
}
+
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
+
if (!ast_strlen_zero(p->moh))
snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
if (agent_status)
@@ -2381,12 +2460,16 @@
AST_LIST_LOCK(&agents);
AST_LIST_TRAVERSE(&agents, p, list) {
+ struct ast_channel *owner;
+
data_agent = ast_data_add_node(data_root, "agent");
if (!data_agent) {
continue;
}
ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
+
if (!(p->pending)) {
ast_data_add_str(data_agent, "id", p->agent);
ast_data_add_structure(agent_pvt, data_agent, p);
@@ -2397,17 +2480,25 @@
if (!data_channel) {
ast_mutex_unlock(&p->lock);
ast_data_remove_node(data_root, data_agent);
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
continue;
}
ast_channel_data_add_structure(data_channel, p->chan, 0);
- if (p->owner && ast_bridged_channel(p->owner)) {
+ if (owner && ast_bridged_channel(owner)) {
data_talkingto = ast_data_add_node(data_agent, "talkingto");
if (!data_talkingto) {
ast_mutex_unlock(&p->lock);
ast_data_remove_node(data_root, data_agent);
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
continue;
}
- ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(p->owner), 0);
+ ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
}
} else {
ast_data_add_node(data_agent, "talkingto");
@@ -2415,6 +2506,12 @@
}
ast_data_add_str(data_agent, "musiconhold", p->moh);
}
+
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
+
ast_mutex_unlock(&p->lock);
/* if this agent doesn't match remove the added agent. */
Modified: tags/1.8.9.1/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.9.1/channels/chan_sip.c?view=diff&rev=354210&r1=354209&r2=354210
==============================================================================
--- tags/1.8.9.1/channels/chan_sip.c (original)
+++ tags/1.8.9.1/channels/chan_sip.c Mon Feb 6 15:40:37 2012
@@ -9122,6 +9122,10 @@
/* Ensure RTCP is enabled since it may be inactive
if we're coming back from a T.38 session */
ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1);
+ /* Ensure audio RTCP reads are enabled */
+ if (p->owner) {
+ ast_channel_set_fd(p->owner, 1, ast_rtp_instance_fd(p->rtp, 1));
+ }
if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) {
ast_clear_flag(&p->flags[0], SIP_DTMF);
@@ -9138,6 +9142,10 @@
} else if (udptlportno > 0) {
if (debug)
ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session.\n");
+ /* Prevent audio RTCP reads */
+ if (p->owner) {
+ ast_channel_set_fd(p->owner, 1, -1);
+ }
/* Silence RTCP while audio RTP is inactive */
ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 0);
} else {
More information about the asterisk-commits
mailing list