diff options
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_dahdi.c | 3 | ||||
-rw-r--r-- | channels/chan_iax2.c | 189 | ||||
-rw-r--r-- | channels/chan_mgcp.c | 3 | ||||
-rw-r--r-- | channels/chan_sip.c | 108 | ||||
-rw-r--r-- | channels/sig_analog.c | 4 | ||||
-rw-r--r-- | channels/sip/include/sip.h | 3 |
6 files changed, 172 insertions, 138 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 05b992402..aa3c71fd8 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -10324,7 +10324,8 @@ static void *analog_ss_thread(void *data) ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) { /* This is a three way call, the main call being a real channel, and we're parking the first call. */ - ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL); + ast_masq_park_call_exten(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), + chan, exten, chan->context, 0, NULL); ast_verb(3, "Parking call to '%s'\n", chan->name); break; } else if (p->hidecallerid && !strcmp(exten, "*82")) { 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; diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 502b929b6..9df36eb7a 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -3133,7 +3133,8 @@ static void *mgcp_ss(void *data) sub->next->owner && ast_bridged_channel(sub->next->owner)) { /* This is a three way call, the main call being a real channel, and we're parking the first call. */ - ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL); + ast_masq_park_call_exten(ast_bridged_channel(sub->next->owner), chan, + p->dtmf_buf, chan->context, 0, NULL); ast_verb(3, "Parking call to '%s'\n", chan->name); break; } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) { diff --git a/channels/chan_sip.c b/channels/chan_sip.c index fcc0dfbd5..c7b39b8b6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1289,7 +1289,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag); static void check_pendings(struct sip_pvt *p); static void *sip_park_thread(void *stuff); -static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, char *parkexten); +static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, const char *park_exten, const char *park_context); static void *sip_pickup_thread(void *stuff); static int sip_pickup(struct ast_channel *chan); @@ -21438,32 +21438,16 @@ static void *sip_park_thread(void *stuff) { struct ast_channel *transferee, *transferer; /* Chan1: The transferee, Chan2: The transferer */ struct sip_dual *d; - struct sip_request req = {0,}; int ext; int res; d = stuff; transferee = d->chan1; transferer = d->chan2; - copy_request(&req, &d->req); - if (!transferee || !transferer) { - ast_log(LOG_ERROR, "Missing channels for parking! Transferer %s Transferee %s\n", transferer ? "<available>" : "<missing>", transferee ? "<available>" : "<missing>" ); - deinit_req(&d->req); - ast_free(d); - return NULL; - } ast_debug(4, "SIP Park: Transferer channel %s, Transferee %s\n", transferer->name, transferee->name); - if (ast_do_masquerade(transferee)) { - ast_log(LOG_WARNING, "Masquerade failed.\n"); - transmit_response(transferer->tech_pvt, "503 Internal error", &req); - deinit_req(&d->req); - ast_free(d); - return NULL; - } - - res = ast_park_call(transferee, transferer, 0, d->parkexten, &ext); + res = ast_park_call_exten(transferee, transferer, d->park_exten, d->park_context, 0, &ext); #ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE if (res) { @@ -21491,31 +21475,40 @@ static void *sip_park_thread(void *stuff) /* Do not hangup call */ } deinit_req(&d->req); + ast_free(d->park_exten); + ast_free(d->park_context); ast_free(d); return NULL; } -/*! \brief Park a call using the subsystem in res_features.c - This is executed in a separate thread -*/ -static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, char *parkexten) +/*! DO NOT hold any locks while calling sip_park */ +static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, const char *park_exten, const char *park_context) { struct sip_dual *d; struct ast_channel *transferee, *transferer; - /* Chan2m: The transferer, chan1m: The transferee */ pthread_t th; transferee = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan1->accountcode, chan1->exten, chan1->context, chan1->linkedid, chan1->amaflags, "Parking/%s", chan1->name); transferer = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->linkedid, chan2->amaflags, "SIPPeer/%s", chan2->name); - if ((!transferer) || (!transferee)) { + d = ast_calloc(1, sizeof(*d)); + if (!transferee || !transferer || !d) { if (transferee) { - transferee->hangupcause = AST_CAUSE_SWITCH_CONGESTION; ast_hangup(transferee); } if (transferer) { - transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION; ast_hangup(transferer); } + ast_free(d); + return -1; + } + d->park_exten = ast_strdup(park_exten); + d->park_context = ast_strdup(park_context); + if (!d->park_exten || !d->park_context) { + ast_hangup(transferee); + ast_hangup(transferer); + ast_free(d->park_exten); + ast_free(d->park_context); + ast_free(d); return -1; } @@ -21524,67 +21517,56 @@ static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct transferee->writeformat = chan1->writeformat; /* Prepare for taking over the channel */ - ast_channel_masquerade(transferee, chan1); + if (ast_channel_masquerade(transferee, chan1)) { + ast_hangup(transferee); + ast_hangup(transferer); + ast_free(d->park_exten); + ast_free(d->park_context); + ast_free(d); + return -1; + } /* Setup the extensions and such */ ast_copy_string(transferee->context, chan1->context, sizeof(transferee->context)); ast_copy_string(transferee->exten, chan1->exten, sizeof(transferee->exten)); transferee->priority = chan1->priority; - + + ast_do_masquerade(transferee); + /* We make a clone of the peer channel too, so we can play back the announcement */ /* Make formats okay */ transferer->readformat = chan2->readformat; transferer->writeformat = chan2->writeformat; - if (!ast_strlen_zero(chan2->parkinglot)) - ast_string_field_set(transferer, parkinglot, chan2->parkinglot); - - /* Prepare for taking over the channel. Go ahead and grab this channel - * lock here to avoid a deadlock with callbacks into the channel driver - * that hold the channel lock and want the pvt lock. */ - while (ast_channel_trylock(chan2)) { - struct sip_pvt *pvt = chan2->tech_pvt; - sip_pvt_unlock(pvt); - usleep(1); - sip_pvt_lock(pvt); + ast_string_field_set(transferer, parkinglot, chan2->parkinglot); + + /* Prepare for taking over the channel */ + if (ast_channel_masquerade(transferer, chan2)) { + ast_hangup(transferer); + ast_free(d->park_exten); + ast_free(d->park_context); + ast_free(d); + return -1; } - ast_channel_masquerade(transferer, chan2); - ast_channel_unlock(chan2); /* Setup the extensions and such */ ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context)); ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten)); transferer->priority = chan2->priority; - if (ast_do_masquerade(transferer)) { - ast_log(LOG_WARNING, "Masquerade failed :(\n"); - transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION; - ast_hangup(transferer); - return -1; - } - if (!transferer || !transferee) { - if (!transferer) { - ast_debug(1, "No transferer channel, giving up parking\n"); - } - if (!transferee) { - ast_debug(1, "No transferee channel, giving up parking\n"); - } - return -1; - } - if (!(d = ast_calloc(1, sizeof(*d)))) { - return -1; - } + ast_do_masquerade(transferer); /* Save original request for followup */ copy_request(&d->req, req); d->chan1 = transferee; /* Transferee */ d->chan2 = transferer; /* Transferer */ d->seqno = seqno; - d->parkexten = parkexten; if (ast_pthread_create_detached_background(&th, NULL, sip_park_thread, d) < 0) { /* Could not start thread */ deinit_req(&d->req); + ast_free(d->park_exten); + ast_free(d->park_context); ast_free(d); /* We don't need it anymore. If thread is created, d will be free'd by sip_park_thread() */ return -1; @@ -23611,6 +23593,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int callid = ast_strdupa(p->callid); localtransfer = p->refer->localtransfer; attendedtransfer = p->refer->attendedtransfer; + if (!*nounlock) { ast_channel_unlock(p->owner); *nounlock = 1; @@ -23619,9 +23602,6 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int /* Parking a call. DO NOT hold any locks while calling ast_parking_ext_valid() */ if (localtransfer && ast_parking_ext_valid(refer_to, current.chan1, current.chan1->context)) { - - copy_request(¤t.req, req); - sip_pvt_lock(p); ast_clear_flag(&p->flags[0], SIP_GOTREFER); p->refer->status = REFER_200OK; @@ -23650,7 +23630,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int } /* DO NOT hold any locks while calling sip_park */ - if (sip_park(current.chan2, current.chan1, req, seqno, refer_to)) { + if (sip_park(current.chan2, current.chan1, req, seqno, refer_to, current.chan1->context)) { sip_pvt_lock(p); transmit_notify_with_sipfrag(p, seqno, "500 Internal Server Error", TRUE); } else { diff --git a/channels/sig_analog.c b/channels/sig_analog.c index 4789f964c..003563767 100644 --- a/channels/sig_analog.c +++ b/channels/sig_analog.c @@ -2261,7 +2261,9 @@ static void *__analog_ss_thread(void *data) ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) { /* This is a three way call, the main call being a real channel, and we're parking the first call. */ - ast_masq_park_call(ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner), chan, 0, NULL); + ast_masq_park_call_exten( + ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner), chan, exten, + chan->context, 0, NULL); ast_verb(3, "Parking call to '%s'\n", chan->name); break; } else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) { diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index fc75ff4fa..c2924b710 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -805,7 +805,8 @@ struct sip_dual { struct ast_channel *chan2; /*!< Second channel involved */ struct sip_request req; /*!< Request that caused the transfer (REFER) */ int seqno; /*!< Sequence number */ - const char *parkexten; + char *park_exten; + char *park_context; }; /*! \brief Parameters to the transmit_invite function */ |