mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-19 08:11:21 +00:00
Merged revisions 294349 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r294349 | rmudgett | 2010-11-09 10:55:32 -0600 (Tue, 09 Nov 2010) | 17 lines Analog lines do not transfer CONNECTED LINE or execute the interception macros. Add connected line update for sig_analog transfers and simplify the corresponding sig_pri and chan_misdn transfer code. Note that if you create a three-way call in sig_analog before transferring the call, the distinction of the caller/callee interception macros make little sense. The interception macro writer needs to be prepared for either caller/callee macro to be executed. The current implementation swaps which caller/callee interception macro is executed after a three-way call is created. Review: https://reviewboard.asterisk.org/r/996/ JIRA ABE-2589 JIRA SWP-2372 ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@294351 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -1882,42 +1882,6 @@ static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd
|
||||
}
|
||||
#endif /* defined(HAVE_PRI_MCID) */
|
||||
|
||||
#if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Copy the source connected line information to the destination for a transfer.
|
||||
* \since 1.8
|
||||
*
|
||||
* \param dest Destination connected line
|
||||
* \param src Source connected line
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void sig_pri_connected_line_copy_transfer(struct ast_party_connected_line *dest, struct ast_party_connected_line *src)
|
||||
{
|
||||
struct ast_party_connected_line connected;
|
||||
|
||||
connected = *src;
|
||||
connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
|
||||
|
||||
/* Make sure empty strings will be erased. */
|
||||
if (!connected.id.name.str) {
|
||||
connected.id.name.str = "";
|
||||
}
|
||||
if (!connected.id.number.str) {
|
||||
connected.id.number.str = "";
|
||||
}
|
||||
if (!connected.id.subaddress.str) {
|
||||
connected.id.subaddress.str = "";
|
||||
}
|
||||
if (!connected.id.tag) {
|
||||
connected.id.tag = "";
|
||||
}
|
||||
|
||||
ast_party_connected_line_copy(dest, &connected);
|
||||
}
|
||||
#endif /* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
|
||||
|
||||
#if defined(HAVE_PRI_TRANSFER)
|
||||
struct xfer_rsp_data {
|
||||
struct sig_pri_span *pri;
|
||||
@@ -1988,16 +1952,12 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
|
||||
int chanpos;
|
||||
};
|
||||
int retval;
|
||||
int transferee_is_held;
|
||||
struct ast_channel *transferee;
|
||||
struct attempt_xfer_call *call_1;
|
||||
struct attempt_xfer_call *call_2;
|
||||
struct attempt_xfer_call *target;
|
||||
struct attempt_xfer_call *swap_call;
|
||||
struct attempt_xfer_call c1;
|
||||
struct attempt_xfer_call c2;
|
||||
struct ast_party_connected_line target_colp;
|
||||
struct ast_party_connected_line transferee_colp;
|
||||
|
||||
c1.pri = call_1_pri;
|
||||
c1.held = call_1_held;
|
||||
@@ -2083,20 +2043,13 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
|
||||
return -1;
|
||||
}
|
||||
|
||||
target = call_2;
|
||||
ast_verb(3, "TRANSFERRING %s to %s\n", call_1->ast->name, target->ast->name);
|
||||
|
||||
ast_party_connected_line_init(&target_colp);
|
||||
sig_pri_connected_line_copy_transfer(&target_colp, &target->ast->connected);
|
||||
ast_party_connected_line_init(&transferee_colp);
|
||||
sig_pri_connected_line_copy_transfer(&transferee_colp, &call_1->ast->connected);
|
||||
transferee_is_held = call_1->held;
|
||||
ast_verb(3, "TRANSFERRING %s to %s\n", call_1->ast->name, call_2->ast->name);
|
||||
|
||||
/*
|
||||
* Setup transfer masquerade.
|
||||
*
|
||||
* Note: There is an extremely nasty deadlock avoidance issue
|
||||
* with ast_channel_masquerade(). Deadlock may be possible if
|
||||
* with ast_channel_transfer_masquerade(). Deadlock may be possible if
|
||||
* the channels involved are proxies (chan_agent channels) and
|
||||
* it is called with locks. Unfortunately, there is no simple
|
||||
* or even merely difficult way to guarantee deadlock avoidance
|
||||
@@ -2104,45 +2057,17 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
|
||||
* possibility of the bridged channel hanging up on us.
|
||||
*/
|
||||
ast_mutex_unlock(&pri->lock);
|
||||
retval = ast_channel_masquerade(target->ast, transferee);
|
||||
if (retval) {
|
||||
/* Masquerade setup failed. */
|
||||
ast_party_connected_line_free(&target_colp);
|
||||
ast_party_connected_line_free(&transferee_colp);
|
||||
retval = ast_channel_transfer_masquerade(
|
||||
call_2->ast,
|
||||
&call_2->ast->connected,
|
||||
call_2->held,
|
||||
transferee,
|
||||
&call_1->ast->connected,
|
||||
call_1->held);
|
||||
|
||||
ast_mutex_lock(&pri->lock);
|
||||
|
||||
ast_channel_unlock(call_1->ast);
|
||||
ast_channel_unlock(call_2->ast);
|
||||
sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
|
||||
sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
|
||||
|
||||
if (rsp_callback) {
|
||||
/* Transfer failed. */
|
||||
rsp_callback(data, 0);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release any hold on the transferee channel before allowing
|
||||
* the masquerade to happen.
|
||||
*/
|
||||
if (transferee_is_held) {
|
||||
ast_indicate(transferee, AST_CONTROL_UNHOLD);
|
||||
}
|
||||
/* Reacquire the pri->lock to hold off completion of the transfer masquerade. */
|
||||
ast_mutex_lock(&pri->lock);
|
||||
|
||||
/*
|
||||
* Before manually completing a masquerade, all channel and pvt
|
||||
* locks must be unlocked. Any recursive channel locks held
|
||||
* before ast_do_masquerade() invalidates channel container
|
||||
* locking order. Since we are unlocking both the pvt and its
|
||||
* owner channel it is possible for "target" to be destroyed
|
||||
* in the pbx thread. To prevent this we must give "target"
|
||||
* a reference before any unlocking takes place.
|
||||
*/
|
||||
ao2_ref(target->ast, +1);
|
||||
ast_channel_unlock(call_1->ast);
|
||||
ast_channel_unlock(call_2->ast);
|
||||
sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
|
||||
@@ -2150,75 +2075,15 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
|
||||
|
||||
if (rsp_callback) {
|
||||
/*
|
||||
* Transfer successful.
|
||||
* Report transfer status.
|
||||
*
|
||||
* Must do the callback before releasing the pri->lock to ensure
|
||||
* Must do the callback before the masquerade completes to ensure
|
||||
* that the protocol message goes out before the call leg is
|
||||
* disconnected.
|
||||
*/
|
||||
rsp_callback(data, 1);
|
||||
rsp_callback(data, retval ? 0 : 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure masquerade is complete.
|
||||
*
|
||||
* After the masquerade, the "target" channel pointer actually
|
||||
* points to the new transferee channel and the bridged channel
|
||||
* is still the intended target of the transfer.
|
||||
*
|
||||
* By manually completing the masquerade, we can send the unhold
|
||||
* and connected line updates where they need to go.
|
||||
*/
|
||||
ast_mutex_unlock(&pri->lock);
|
||||
ast_do_masquerade(target->ast);
|
||||
|
||||
/* Release any hold on the target. */
|
||||
if (target->held) {
|
||||
ast_queue_control(target->ast, AST_CONTROL_UNHOLD);
|
||||
}
|
||||
|
||||
/* Transfer COLP between target and transferee channels. */
|
||||
{
|
||||
/*
|
||||
* Since "target" may not actually be bridged to another
|
||||
* channel, there is no way for us to queue a frame so that its
|
||||
* connected line status will be updated. Instead, we use the
|
||||
* somewhat hackish approach of using a special control frame
|
||||
* type that instructs ast_read() to perform a specific action.
|
||||
* In this case, the frame we queue tells ast_read() to call the
|
||||
* connected line interception macro configured for "target".
|
||||
*/
|
||||
struct ast_control_read_action_payload *frame_payload;
|
||||
int payload_size;
|
||||
int frame_size;
|
||||
unsigned char connected_line_data[1024];
|
||||
|
||||
payload_size = ast_connected_line_build_data(connected_line_data,
|
||||
sizeof(connected_line_data), &target_colp, NULL);
|
||||
if (payload_size != -1) {
|
||||
frame_size = payload_size + sizeof(*frame_payload);
|
||||
frame_payload = alloca(frame_size);
|
||||
frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
|
||||
frame_payload->payload_size = payload_size;
|
||||
memcpy(frame_payload->payload, connected_line_data, payload_size);
|
||||
ast_queue_control_data(target->ast, AST_CONTROL_READ_ACTION, frame_payload,
|
||||
frame_size);
|
||||
}
|
||||
/*
|
||||
* In addition to queueing the read action frame so that the
|
||||
* connected line info on "target" will be updated, we also
|
||||
* are going to queue a plain old connected line update on
|
||||
* "target" to update the target channel.
|
||||
*/
|
||||
ast_channel_queue_connected_line_update(target->ast, &transferee_colp, NULL);
|
||||
}
|
||||
|
||||
ast_party_connected_line_free(&target_colp);
|
||||
ast_party_connected_line_free(&transferee_colp);
|
||||
|
||||
ao2_ref(target->ast, -1);
|
||||
ast_mutex_lock(&pri->lock);
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
#endif /* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user