mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
res_pjsip_refer: Fix bugs involving Parking/PJSIP/transfers
PJSIP would never send the final 200 Notify for a blind transfer when transferring to parking. This patch fixes that. In addition, it fixes a reference leak when performing blind transfers to non-bridging extensions. Review: https://reviewboard.asterisk.org/r/3485/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/12@414400 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -3718,7 +3718,7 @@ struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channe
|
||||
*/
|
||||
static enum ast_transfer_result blind_transfer_bridge(struct ast_channel *transferer,
|
||||
struct ast_bridge *bridge, const char *exten, const char *context,
|
||||
transfer_channel_cb new_channel_cb, void *user_data)
|
||||
transfer_channel_cb new_channel_cb, struct transfer_channel_data *user_data_wrapper)
|
||||
{
|
||||
struct ast_channel *local;
|
||||
char chan_name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
|
||||
@@ -3734,7 +3734,7 @@ static enum ast_transfer_result blind_transfer_bridge(struct ast_channel *transf
|
||||
pbx_builtin_setvar_helper(local, BLINDTRANSFER, ast_channel_name(transferer));
|
||||
|
||||
if (new_channel_cb) {
|
||||
new_channel_cb(local, user_data, AST_BRIDGE_TRANSFER_MULTI_PARTY);
|
||||
new_channel_cb(local, user_data_wrapper, AST_BRIDGE_TRANSFER_MULTI_PARTY);
|
||||
}
|
||||
|
||||
if (ast_call(local, chan_name, 0)) {
|
||||
@@ -3968,7 +3968,9 @@ static struct ast_channel *get_transferee(struct ao2_container *channels, struct
|
||||
return transferee;
|
||||
}
|
||||
|
||||
static enum ast_transfer_result try_parking(struct ast_channel *transferer, const char *context, const char *exten)
|
||||
static enum ast_transfer_result try_parking(struct ast_channel *transferer,
|
||||
const char *context, const char *exten, transfer_channel_cb new_channel_cb,
|
||||
struct transfer_channel_data *user_data_wrapper)
|
||||
{
|
||||
RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup);
|
||||
|
||||
@@ -3985,7 +3987,7 @@ static enum ast_transfer_result try_parking(struct ast_channel *transferer, cons
|
||||
}
|
||||
|
||||
if (ast_parking_blind_transfer_park(transferer_bridge_channel,
|
||||
context, exten)) {
|
||||
context, exten, new_channel_cb, user_data_wrapper)) {
|
||||
return AST_BRIDGE_TRANSFER_FAIL;
|
||||
}
|
||||
|
||||
@@ -4089,6 +4091,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
|
||||
RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_channel *, transferee, NULL, ast_channel_cleanup);
|
||||
RAII_VAR(struct transfer_channel_data *, user_data_wrapper, NULL, ao2_cleanup);
|
||||
int do_bridge_transfer;
|
||||
int transfer_prohibited;
|
||||
enum ast_transfer_result transfer_result;
|
||||
@@ -4106,14 +4109,25 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
|
||||
goto publish;
|
||||
}
|
||||
|
||||
user_data_wrapper = ao2_alloc(sizeof(*user_data_wrapper), NULL);
|
||||
if (!user_data_wrapper) {
|
||||
transfer_result = AST_BRIDGE_TRANSFER_FAIL;
|
||||
goto publish;
|
||||
}
|
||||
|
||||
user_data_wrapper->data = user_data;
|
||||
|
||||
/* Take off hold if they are on hold. */
|
||||
ast_bridge_channel_write_unhold(bridge_channel);
|
||||
|
||||
transfer_result = try_parking(transferer, context, exten);
|
||||
transfer_result = try_parking(transferer, context, exten, new_channel_cb, user_data_wrapper);
|
||||
if (transfer_result == AST_BRIDGE_TRANSFER_SUCCESS) {
|
||||
goto publish;
|
||||
}
|
||||
|
||||
/* Since parking didn't take control of the user_data_wrapper, we are just going to raise the completed flag now. */
|
||||
user_data_wrapper->completed = 1;
|
||||
|
||||
{
|
||||
SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock);
|
||||
|
||||
@@ -4142,7 +4156,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
|
||||
|
||||
if (do_bridge_transfer) {
|
||||
transfer_result = blind_transfer_bridge(transferer, bridge, exten, context,
|
||||
new_channel_cb, user_data);
|
||||
new_channel_cb, user_data_wrapper);
|
||||
goto publish;
|
||||
}
|
||||
|
||||
@@ -4155,7 +4169,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
|
||||
}
|
||||
|
||||
if (bridge_channel_internal_queue_blind_transfer(transferee, exten, context,
|
||||
new_channel_cb, user_data)) {
|
||||
new_channel_cb, user_data_wrapper)) {
|
||||
transfer_result = AST_BRIDGE_TRANSFER_FAIL;
|
||||
goto publish;
|
||||
}
|
||||
|
@@ -3145,10 +3145,10 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void blind_transfer_cb(struct ast_channel *new_channel, void *user_data,
|
||||
static void blind_transfer_cb(struct ast_channel *new_channel, struct transfer_channel_data *user_data_wrapper,
|
||||
enum ast_transfer_type transfer_type)
|
||||
{
|
||||
struct ast_channel *transferer_channel = user_data;
|
||||
struct ast_channel *transferer_channel = user_data_wrapper->data;
|
||||
|
||||
if (transfer_type == AST_BRIDGE_TRANSFER_MULTI_PARTY) {
|
||||
copy_caller_data(new_channel, transferer_channel);
|
||||
|
@@ -142,7 +142,9 @@ int ast_parking_park_bridge_channel(struct ast_bridge_channel *parkee, const cha
|
||||
return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
|
||||
}
|
||||
|
||||
int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context, const char *exten)
|
||||
int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker,
|
||||
const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
|
||||
struct transfer_channel_data *parked_channel_data)
|
||||
{
|
||||
RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
|
||||
ao2_global_obj_ref(parking_provider), ao2_cleanup);
|
||||
@@ -153,10 +155,10 @@ int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const cha
|
||||
|
||||
if (table->module_info) {
|
||||
SCOPED_MODULE_USE(table->module_info->self);
|
||||
return table->parking_blind_transfer_park(parker, context, exten);
|
||||
return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
|
||||
}
|
||||
|
||||
return table->parking_blind_transfer_park(parker, context, exten);
|
||||
return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
|
||||
}
|
||||
|
||||
int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
|
||||
|
Reference in New Issue
Block a user