summaryrefslogtreecommitdiff
path: root/main/core_local.c
diff options
context:
space:
mode:
authorKevin Harwell <kharwell@digium.com>2016-03-01 16:18:21 -0600
committerKevin Harwell <kharwell@digium.com>2016-03-03 14:03:14 -0600
commit15c5743ac1371535441e2111499d848dd9c5ff52 (patch)
tree2118adf804cd135ff9074f1d98df5a81f77adf34 /main/core_local.c
parent7023055def57fe63bb169c481c801c72599d3fdb (diff)
bridge.c: Crash during attended transfer when missing a local channel half
It's possible for the transferer channel to get hung up early during the attended transfer process. For instance, a phone may send a "bye" immediately upon receiving a sip notify that contains a sip frag 100 (I'm looking at you Jitsi). When this occurs a race begins between the transferer being hung up and completion of the transfer code. If the channel hangs up too early during a transfer involving stasis bridging for instance, then when the created local channel goes to look up its swap channel (and associated datastore) it can't find it (since it is no longer in the bridge) thus it fails to enter the stasis application. Consequently, the created local channel(s) hang up as well. If the timing is just right then the bridging code attempts to add the message link with missing local channel(s). Hence the crash. Unfortunately, there is no great way to solve the problem of the unexpected "bye". While we can't guarantee we won't receive an early hangup, and in this case still fail to enter the stasis application, we can make it so asterisk does not crash. This patch does just that by locking the local channel structure, checking that the local channel's peer has not been lost, and then continuing. This keeps the local channel's peer from being ripped out from underneath it by the local/unreal hangup code while attempting to set the stasis message link. ASTERISK-25771 Change-Id: Ie6d6061e34c7c95f07116fffac9a09e5d225c880
Diffstat (limited to 'main/core_local.c')
-rw-r--r--main/core_local.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/main/core_local.c b/main/core_local.c
index f81c71cd6..6644aaf50 100644
--- a/main/core_local.c
+++ b/main/core_local.c
@@ -235,6 +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)
+{
+ struct local_pvt *p = ast_channel_tech_pvt(chan);
+
+ *outchan = NULL;
+ *outowner = NULL;
+
+ if (p) {
+ ao2_ref(p, 1);
+ ast_unreal_lock_all(&p->base, outchan, outowner);
+ }
+}
+
+void ast_local_unlock_all(struct ast_channel *chan)
+{
+ struct local_pvt *p = ast_channel_tech_pvt(chan);
+ struct ast_unreal_pvt *base;
+
+ if (!p) {
+ return;
+ }
+
+ 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);
+}
+
struct ast_channel *ast_local_get_peer(struct ast_channel *ast)
{
struct local_pvt *p = ast_channel_tech_pvt(ast);