summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_dahdi.c3
-rw-r--r--channels/chan_iax2.c189
-rw-r--r--channels/chan_mgcp.c3
-rw-r--r--channels/chan_sip.c108
-rw-r--r--channels/sig_analog.c4
-rw-r--r--channels/sip/include/sip.h3
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(&current.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 */