int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(newchan); struct ast_bridge *bridge_owner; struct ast_bridge *bridge_chan; if (!p) { return -1; } ao2_lock(p); if ((p->owner != oldchan) && (p->chan != oldchan)) { ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan); ao2_unlock(p); return -1; } if (p->owner == oldchan) { p->owner = newchan; } else { p->chan = newchan; } if (ast_check_hangup(newchan) || !p->owner || !p->chan) { ao2_unlock(p); return 0; } /* Do not let a masquerade cause an unreal channel to be bridged to itself! */ bridge_owner = ast_channel_internal_bridge(p->owner); bridge_chan = ast_channel_internal_bridge(p->chan); if (bridge_owner && bridge_owner == bridge_chan) { ast_log(LOG_WARNING, "You can not bridge an unreal channel (%s) to itself!\n", ast_channel_name(newchan)); ao2_unlock(p); ast_queue_hangup(newchan); return -1; } ao2_unlock(p); return 0; }
/*! \brief Helper function to not deadlock when queueing the hangup frame */ static void bridge_queue_hangup(struct bridge_pvt *p, struct ast_channel *us) { struct ast_channel *other = (p->input == us ? p->output : p->input); while (other && ast_channel_trylock(other)) { ast_mutex_unlock(&p->lock); do { CHANNEL_DEADLOCK_AVOIDANCE(us); } while (ast_mutex_trylock(&p->lock)); other = (p->input == us ? p->output : p->input); } /* We basically queue the frame up on the other channel if present */ if (other) { ast_queue_hangup(other); ast_channel_unlock(other); } return; }