mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-05 20:55:26 +00:00
core_local: local channel data not being properly unref'ed and unlocked
In an earlier version of Asterisk a local channel [un]lock all functions were added in order to keep a crash from occurring when a channel hung up too early during an attended transfer. Unfortunately, when a transfer failure occurs and depending on the timing, the local channels sometime do not get properly unlocked and deref'ed after being locked and ref'ed. This happens because the underlying local channel structure gets NULLed out before unlocking. This patch reworks those [un]lock functions and makes sure the values that get locked and ref'ed later get unlocked and deref'ed. ASTERISK-27074 #close Change-Id: Ice96653e29bd9d6674ed5f95feb6b448ab148b09
This commit is contained in:
@@ -235,17 +235,45 @@ struct local_pvt {
|
||||
char exten[AST_MAX_EXTENSION];
|
||||
};
|
||||
|
||||
void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan,
|
||||
struct ast_channel **outowner)
|
||||
void ast_local_lock_all2(struct ast_channel *chan, void **tech_pvt,
|
||||
struct ast_channel **base_chan, struct ast_channel **base_owner)
|
||||
{
|
||||
struct local_pvt *p = ast_channel_tech_pvt(chan);
|
||||
|
||||
*outchan = NULL;
|
||||
*outowner = NULL;
|
||||
*tech_pvt = NULL;
|
||||
*base_chan = NULL;
|
||||
*base_owner = NULL;
|
||||
|
||||
if (p) {
|
||||
ao2_ref(p, 1);
|
||||
ast_unreal_lock_all(&p->base, outchan, outowner);
|
||||
*tech_pvt = ao2_bump(p);
|
||||
ast_unreal_lock_all(&p->base, base_chan, base_owner);
|
||||
}
|
||||
}
|
||||
|
||||
void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan,
|
||||
struct ast_channel **outowner)
|
||||
{
|
||||
void *tech_pvt;
|
||||
ast_local_lock_all2(chan, &tech_pvt, outchan, outowner);
|
||||
}
|
||||
|
||||
void ast_local_unlock_all2(void *tech_pvt, struct ast_channel *base_chan,
|
||||
struct ast_channel *base_owner)
|
||||
{
|
||||
if (base_chan) {
|
||||
ast_channel_unlock(base_chan);
|
||||
ast_channel_unref(base_chan);
|
||||
}
|
||||
|
||||
if (base_owner) {
|
||||
ast_channel_unlock(base_owner);
|
||||
ast_channel_unref(base_owner);
|
||||
}
|
||||
|
||||
if (tech_pvt) {
|
||||
struct local_pvt *p = tech_pvt;
|
||||
ao2_unlock(&p->base);
|
||||
ao2_ref(tech_pvt, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,19 +287,7 @@ void ast_local_unlock_all(struct ast_channel *chan)
|
||||
}
|
||||
|
||||
base = &p->base;
|
||||
|
||||
if (base->owner) {
|
||||
ast_channel_unlock(base->owner);
|
||||
ast_channel_unref(base->owner);
|
||||
}
|
||||
|
||||
if (base->chan) {
|
||||
ast_channel_unlock(base->chan);
|
||||
ast_channel_unref(base->chan);
|
||||
}
|
||||
|
||||
ao2_unlock(base);
|
||||
ao2_ref(p, -1);
|
||||
ast_local_unlock_all2(p, base->chan, base->owner);
|
||||
}
|
||||
|
||||
struct ast_channel *ast_local_get_peer(struct ast_channel *ast)
|
||||
|
Reference in New Issue
Block a user