diff options
author | George Joseph <gjoseph@digium.com> | 2018-04-10 10:10:52 -0500 |
---|---|---|
committer | Gerrit Code Review <gerrit2@gerrit.digium.api> | 2018-04-10 10:10:52 -0500 |
commit | 8af759c088b845f991e9701f4915adef8a3d1f40 (patch) | |
tree | 9fad6dfc225881f4f59cb20d06a9167bd5aae117 | |
parent | 2a6072a9c414a8fb7ecb1b6598873e60ef8cadf2 (diff) | |
parent | d72a2966da39c56c7dbf14e04ba7a6aa302aa2f1 (diff) |
Merge "chan_sip.c: Fix INVITE with replaces channel ref leak."
-rw-r--r-- | channels/chan_sip.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 138021e82..c357785ab 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -25856,7 +25856,7 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int *nounlock, struct sip_pvt *replaces_pvt, struct ast_channel *replaces_chan) { struct ast_channel *c; - RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup); + struct ast_bridge *bridge; if (req->ignore) { return 0; @@ -25872,6 +25872,7 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, } append_history(p, "Xfer", "INVITE/Replace received"); + /* Get a ref to ensure the channel cannot go away on us. */ c = ast_channel_ref(p->owner); /* Fake call progress */ @@ -25891,16 +25892,22 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, ast_channel_unlock(replaces_chan); if (bridge) { + /* + * We have two refs of the channel. One is held in c and the other + * is notionally represented by p->owner. The impart is "stealing" + * the p->owner ref on success so the bridging system can have + * control of when the channel is hung up. + */ if (ast_bridge_impart(bridge, c, replaces_chan, NULL, AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { ast_hangup(c); - ast_channel_unref(c); } + ao2_ref(bridge, -1); } else { ast_channel_move(replaces_chan, c); ast_hangup(c); - ast_channel_unref(c); } + ast_channel_unref(c); sip_pvt_lock(p); return 0; } |