diff options
author | Richard Mudgett <rmudgett@digium.com> | 2011-10-18 21:15:45 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2011-10-18 21:15:45 +0000 |
commit | 10de040b6e89e7c973c23353d477c5dd465a14df (patch) | |
tree | 25a7d164a2b8276213348bc5f63fe7c6ed9af4cf /channels/chan_iax2.c | |
parent | d19ddf87410ce65071cf92c298bf048f3ab0f9bb (diff) |
More parking issues.
* Fix potential deadlocks in SIP and IAX blind transfer to parking.
* Fix SIP, IAX, DAHDI analog, and MGCP channel drivers to respect the
parkext_exclusive option with transfers (Park(,,,,,exclusive_lot)
parameter). Created ast_park_call_exten() and ast_masq_park_call_exten()
to maintian API compatibility.
* Made masq_park_call() handle a failed ast_channel_masquerade() setup.
* Reduced excessive struct parkeduser.peername[] size.
........
Merged revisions 341254 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
Merged revisions 341255 from http://svn.asterisk.org/svn/asterisk/branches/10
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@341256 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels/chan_iax2.c')
-rw-r--r-- | channels/chan_iax2.c | 189 |
1 files changed, 119 insertions, 70 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 3d671bc9a..a8369f554 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -9347,78 +9347,125 @@ static void spawn_dp_lookup(int callno, const char *context, const char *calledn struct iax_dual { struct ast_channel *chan1; struct ast_channel *chan2; - const char *parkexten; + char *park_exten; + char *park_context; }; static void *iax_park_thread(void *stuff) { - struct ast_channel *chan1, *chan2; struct iax_dual *d; - struct ast_frame *f; + int res; int ext = 0; d = stuff; - chan1 = d->chan1; - chan2 = d->chan2; + + ast_debug(4, "IAX Park: Transferer channel %s, Transferee %s\n", + d->chan2->name, d->chan1->name); + + res = ast_park_call_exten(d->chan1, d->chan2, d->park_exten, d->park_context, 0, &ext); + if (res) { + /* Parking failed. */ + ast_hangup(d->chan1); + } else { + ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext); + } + ast_hangup(d->chan2); + + ast_free(d->park_exten); + ast_free(d->park_context); ast_free(d); - f = ast_read(chan1); - if (f) - ast_frfree(f); - ast_park_call(chan1, chan2, 0, d->parkexten, &ext); - ast_hangup(chan2); - ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext); return NULL; } -static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2, const char *parkexten) +/*! DO NOT hold any locks while calling iax_park */ +static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2, const char *park_exten, const char *park_context) { struct iax_dual *d; - struct ast_channel *chan1m, *chan2m; + struct ast_channel *chan1m, *chan2m;/* Chan2m: The transferer, chan1m: The transferee */ pthread_t th; + chan1m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan1->exten, chan1->context, chan1->linkedid, chan1->amaflags, "Parking/%s", chan1->name); chan2m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->linkedid, chan2->amaflags, "IAXPeer/%s", chan2->name); - if (chan2m && chan1m) { - /* Make formats okay */ - chan1m->readformat = chan1->readformat; - chan1m->writeformat = chan1->writeformat; - ast_channel_masquerade(chan1m, chan1); - /* Setup the extensions and such */ - ast_copy_string(chan1m->context, chan1->context, sizeof(chan1m->context)); - ast_copy_string(chan1m->exten, chan1->exten, sizeof(chan1m->exten)); - chan1m->priority = chan1->priority; - - /* We make a clone of the peer channel too, so we can play - back the announcement */ - /* Make formats okay */ - chan2m->readformat = chan2->readformat; - chan2m->writeformat = chan2->writeformat; - ast_channel_masquerade(chan2m, chan2); - /* Setup the extensions and such */ - ast_copy_string(chan2m->context, chan2->context, sizeof(chan2m->context)); - ast_copy_string(chan2m->exten, chan2->exten, sizeof(chan2m->exten)); - chan2m->priority = chan2->priority; - if (ast_do_masquerade(chan2m)) { - ast_log(LOG_WARNING, "Masquerade failed :(\n"); - ast_hangup(chan2m); - return -1; - } - } else { - if (chan1m) + d = ast_calloc(1, sizeof(*d)); + if (!chan1m || !chan2m || !d) { + if (chan1m) { ast_hangup(chan1m); - if (chan2m) + } + if (chan2m) { ast_hangup(chan2m); + } + ast_free(d); return -1; } - if ((d = ast_calloc(1, sizeof(*d)))) { - d->chan1 = chan1m; - d->chan2 = chan2m; - d->parkexten = parkexten; - if (!ast_pthread_create_detached_background(&th, NULL, iax_park_thread, d)) { - return 0; - } + d->park_exten = ast_strdup(park_exten); + d->park_context = ast_strdup(park_context); + if (!d->park_exten || !d->park_context) { + ast_hangup(chan1m); + ast_hangup(chan2m); + ast_free(d->park_exten); + ast_free(d->park_context); ast_free(d); + return -1; } - return -1; + + /* Make formats okay */ + chan1m->readformat = chan1->readformat; + chan1m->writeformat = chan1->writeformat; + + /* Prepare for taking over the channel */ + if (ast_channel_masquerade(chan1m, chan1)) { + ast_hangup(chan1m); + ast_hangup(chan2m); + ast_free(d->park_exten); + ast_free(d->park_context); + ast_free(d); + return -1; + } + + /* Setup the extensions and such */ + ast_copy_string(chan1m->context, chan1->context, sizeof(chan1m->context)); + ast_copy_string(chan1m->exten, chan1->exten, sizeof(chan1m->exten)); + chan1m->priority = chan1->priority; + + ast_do_masquerade(chan1m); + + /* We make a clone of the peer channel too, so we can play + back the announcement */ + + /* Make formats okay */ + chan2m->readformat = chan2->readformat; + chan2m->writeformat = chan2->writeformat; + ast_string_field_set(chan2m, parkinglot, chan2->parkinglot); + + /* Prepare for taking over the channel */ + if (ast_channel_masquerade(chan2m, chan2)) { + ast_hangup(chan1m); + ast_hangup(chan2m); + ast_free(d->park_exten); + ast_free(d->park_context); + ast_free(d); + return -1; + } + + /* Setup the extensions and such */ + ast_copy_string(chan2m->context, chan2->context, sizeof(chan2m->context)); + ast_copy_string(chan2m->exten, chan2->exten, sizeof(chan2m->exten)); + chan2m->priority = chan2->priority; + + ast_do_masquerade(chan2m); + + d->chan1 = chan1m; /* Transferee */ + d->chan2 = chan2m; /* Transferer */ + if (ast_pthread_create_detached_background(&th, NULL, iax_park_thread, d) < 0) { + /* Could not start thread */ + ast_hangup(chan1m); + ast_hangup(chan2m); + ast_free(d->park_exten); + ast_free(d->park_context); + ast_free(d); + return -1; + } + return 0; } static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, unsigned int ver) @@ -10795,43 +10842,45 @@ static int socket_process(struct iax2_thread *thread) owner = iaxs[fr->callno]->owner; bridged_chan = owner ? ast_bridged_channel(owner) : NULL; if (bridged_chan && ies.called_number) { + const char *context; + + context = ast_strdupa(iaxs[fr->callno]->context); + + ast_channel_ref(owner); + ast_channel_ref(bridged_chan); + ast_channel_unlock(owner); ast_mutex_unlock(&iaxsl[fr->callno]); /* Set BLINDTRANSFER channel variables */ pbx_builtin_setvar_helper(owner, "BLINDTRANSFER", bridged_chan->name); pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", owner->name); - if (ast_parking_ext_valid(ies.called_number, owner, iaxs[fr->callno]->context)) { + /* DO NOT hold any locks while calling ast_parking_ext_valid() */ + if (ast_parking_ext_valid(ies.called_number, owner, context)) { ast_debug(1, "Parking call '%s'\n", bridged_chan->name); - if (iax_park(bridged_chan, owner, ies.called_number)) { + if (iax_park(bridged_chan, owner, ies.called_number, context)) { ast_log(LOG_WARNING, "Failed to park call '%s'\n", bridged_chan->name); } - ast_mutex_lock(&iaxsl[fr->callno]); } else { - ast_mutex_lock(&iaxsl[fr->callno]); - - if (iaxs[fr->callno]) { - if (ast_async_goto(bridged_chan, iaxs[fr->callno]->context, - ies.called_number, 1)) { - ast_log(LOG_WARNING, - "Async goto of '%s' to '%s@%s' failed\n", - bridged_chan->name, ies.called_number, - iaxs[fr->callno]->context); - } else { - ast_debug(1, "Async goto of '%s' to '%s@%s' started\n", - bridged_chan->name, ies.called_number, - iaxs[fr->callno]->context); - } + if (ast_async_goto(bridged_chan, context, ies.called_number, 1)) { + ast_log(LOG_WARNING, + "Async goto of '%s' to '%s@%s' failed\n", + bridged_chan->name, ies.called_number, context); } else { - /* Initiating call went away before we could transfer. */ + ast_debug(1, "Async goto of '%s' to '%s@%s' started\n", + bridged_chan->name, ies.called_number, context); } } + ast_channel_unref(owner); + ast_channel_unref(bridged_chan); + + ast_mutex_lock(&iaxsl[fr->callno]); } else { ast_debug(1, "Async goto not applicable on call %d\n", fr->callno); - } - if (owner) { - ast_channel_unlock(owner); + if (owner) { + ast_channel_unlock(owner); + } } break; |