Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
Data Structures | Macros | Functions | Variables
res_pjsip_refer.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/bridge.h"
#include "asterisk/framehook.h"
#include "asterisk/stasis_bridges.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/causes.h"
#include "asterisk/refer.h"
Include dependency graph for res_pjsip_refer.c:

Go to the source code of this file.

Data Structures

struct  invite_replaces
 Structure used to retrieve channel from another session. More...
 
struct  refer_attended
 Structure for attended transfer task. More...
 
struct  refer_blind
 Structure for blind transfer callback details. More...
 
struct  refer_data
 
struct  refer_out_of_dialog
 
struct  refer_progress
 REFER Progress structure. More...
 
struct  refer_progress_notification
 REFER Progress notification structure. More...
 
struct  transfer_ari_state
 

Macros

#define DETERMINE_TRANSFER_CONTEXT(context, session)
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static void add_header_from_channel_var (struct ast_channel *chan, const char *var_name, const char *header_name, pjsip_tx_data *tdata)
 Use the value of a channel variable as the value of a SIP header.
 
static int add_refer_param (struct ast_refer_params *params, const char *key, struct pj_str_t *str)
 
static int ari_notify (struct transfer_ari_state *state)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static char * copy_string (struct pj_str_t *str)
 
static int defer_termination_cancel_task (void *data)
 
static int dlg_releaser_task (void *data)
 
static pjsip_uri * get_refer_to_uri (pjsip_tx_data *tdata)
 Helper function which returns the name-addr of the Refer-To header or NULL.
 
static int invite_replaces (void *data)
 Task for invite replaces.
 
static int is_refer_var_blocked (const char *name)
 
static int load_module (void)
 
static struct ast_framerefer_ari_progress_framehook (struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
 Progress monitoring frame hook - examines frames to determine state of transfer. Used for the ari-only mode.
 
static struct refer_attendedrefer_attended_alloc (struct ast_sip_session *transferer, struct ast_sip_session *transferer_second, struct refer_progress *progress)
 Allocator for attended transfer task.
 
static void refer_attended_destroy (void *obj)
 Destructor for attended transfer task.
 
static int refer_attended_task (void *data)
 Task for attended transfer executed by attended->transferer_second serializer.
 
static void refer_blind_callback (struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper, enum ast_transfer_type transfer_type)
 Blind transfer callback function.
 
static void refer_client_on_evsub_state (pjsip_evsub *sub, pjsip_event *event)
 
static struct refer_datarefer_data_create (const struct ast_refer *refer)
 
static void refer_data_destroy (void *obj)
 
static int refer_incoming_ari_request (struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target, pjsip_param *replaces_param, struct refer_progress *progress)
 
static int refer_incoming_attended_request (struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri, pjsip_param *replaces_param, struct refer_progress *progress)
 
static int refer_incoming_blind_request (struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target, struct refer_progress *progress)
 
static int refer_incoming_invite_request (struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 
static int refer_incoming_refer_request (struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 
static int refer_incoming_request (struct ast_sip_session *session, pjsip_rx_data *rdata)
 
static pj_status_t refer_on_tx_request (pjsip_tx_data *tdata)
 
static void refer_out_of_dialog_destroy (void *obj)
 Destructor for REFER out of dialog structure.
 
static void refer_outgoing_request (struct ast_sip_session *session, struct pjsip_tx_data *tdata)
 
static void refer_params_destroy (void *obj)
 
static int refer_progress_alloc (struct ast_sip_session *session, pjsip_rx_data *rdata, struct refer_progress **progress)
 Internal helper function which sets up a refer progress structure if needed.
 
static void refer_progress_bridge (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 
static void refer_progress_destroy (void *obj)
 Destructor for REFER progress sutrcture.
 
static struct ast_framerefer_progress_framehook (struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
 Progress monitoring frame hook - examines frames to determine state of transfer.
 
static void refer_progress_framehook_destroy (void *data)
 Destroy callback for monitoring framehook.
 
static struct refer_progress_notificationrefer_progress_notification_alloc (struct refer_progress *progress, int response, pjsip_evsub_state state)
 Allocator for REFER Progress notification structure.
 
static void refer_progress_notification_destroy (void *obj)
 Destructor for REFER Progress notification structure.
 
static int refer_progress_notify (void *data)
 Serialized callback for subscription notification.
 
static void refer_progress_on_evsub_state (pjsip_evsub *sub, pjsip_event *event)
 Callback for REFER subscription state changes.
 
static int refer_send (void *data)
 
static int refer_unreference_dialog (void *obj)
 
static int session_end_if_deferred_task (void *data)
 
static int sip_refer_send (const struct ast_refer *refer)
 
static void transfer_ari_state_destroy (void *obj)
 Destructor of the state used for the ARI transfer.
 
static int unload_module (void)
 
static enum pjsip_status_code vars_to_headers (const struct ast_refer *refer, pjsip_tx_data *tdata)
 
static int xfer_response_code2sip (enum ast_transfer_result xfer_code)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Blind and Attended Transfer Support" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip,res_pjsip_session,res_pjsip_pubsub", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static pjsip_module refer_out_of_dialog_module
 REFER Out-of-dialog module, used to attach session data structure to subscription.
 
static pjsip_evsub_user refer_progress_evsub_cb
 Callback structure for subscription.
 
static pjsip_module refer_progress_module
 REFER Progress module, used to attach REFER progress structure to subscriptions.
 
static struct ast_taskprocessorrefer_serializer
 
static struct ast_sip_session_supplement refer_supplement
 
static const struct ast_refer_tech refer_tech
 

Macro Definition Documentation

◆ DETERMINE_TRANSFER_CONTEXT

#define DETERMINE_TRANSFER_CONTEXT (   context,
  session 
)

Definition at line 1013 of file res_pjsip_refer.c.

1014 { \
1015 ast_channel_lock((session)->channel); \
1016 context = pbx_builtin_getvar_helper((session)->channel, "TRANSFER_CONTEXT"); \
1017 if (ast_strlen_zero(context)) { \
1018 context = (session)->endpoint->context; \
1019 } else { \
1020 context = ast_strdupa(context); \
1021 } \
1022 ast_channel_unlock((session)->channel); \
1023 } while (0) \
1024
static struct ast_mansession session
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2214 of file res_pjsip_refer.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2214 of file res_pjsip_refer.c.

◆ add_header_from_channel_var()

static void add_header_from_channel_var ( struct ast_channel chan,
const char *  var_name,
const char *  header_name,
pjsip_tx_data *  tdata 
)
static

Use the value of a channel variable as the value of a SIP header.

This looks up a variable name on a channel, then takes that value and adds it to an outgoing SIP request. If the header already exists on the message, then no action is taken.

Precondition
chan is locked.
Parameters
chanThe channel on which to find the variable.
var_nameThe name of the channel variable to use.
header_nameThe name of the SIP header to add to the outgoing message.
tdataThe outgoing SIP message on which to add the header

Definition at line 2129 of file res_pjsip_refer.c.

2130{
2131 const char *var_value;
2132 pj_str_t pj_header_name;
2133 pjsip_hdr *header;
2134
2135 var_value = pbx_builtin_getvar_helper(chan, var_name);
2136 if (ast_strlen_zero(var_value)) {
2137 return;
2138 }
2139
2140 pj_cstr(&pj_header_name, header_name);
2141 header = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_header_name, NULL);
2142 if (header) {
2143 return;
2144 }
2145 ast_sip_add_header(tdata, header_name, var_value);
2146}
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition res_pjsip.c:2006
#define NULL
Definition resample.c:96

References ast_sip_add_header(), ast_strlen_zero(), NULL, and pbx_builtin_getvar_helper().

Referenced by refer_outgoing_request().

◆ add_refer_param()

static int add_refer_param ( struct ast_refer_params params,
const char *  key,
struct pj_str_t *  str 
)
static

Definition at line 1529 of file res_pjsip_refer.c.

1530{
1531 struct ast_refer_param param;
1532
1533 param.param_name = ast_strdup(key);
1534 if (!param.param_name) {
1535 return 0;
1536 }
1537
1538 param.param_value = copy_string(str);
1539 if (!param.param_value) {
1540 ast_free((char *) param.param_name);
1541 return 0;
1542 }
1543
1544 if (AST_VECTOR_APPEND(params, param) != 0) {
1545 ast_free((char *) param.param_name);
1546 ast_free((char *) param.param_value);
1547 return 0;
1548 }
1549 return 1;
1550}
const char * str
Definition app_jack.c:150
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
static char * copy_string(struct pj_str_t *str)
const char * param_name
Definition refer.h:82
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267

References ast_free, ast_strdup, AST_VECTOR_APPEND, copy_string(), ast_refer_param::param_name, ast_refer_param::param_value, and str.

Referenced by refer_incoming_ari_request().

◆ ari_notify()

static int ari_notify ( struct transfer_ari_state state)
static

Definition at line 148 of file res_pjsip_refer.c.

149{
150 int res = 0;
151 SCOPE_ENTER(3, "%s: state: %s\n", ast_channel_name(state->transferer_chan),
152 ast_channel_transfer_state2str(state->last_response));
153
154 res = ast_refer_notify_transfer_request(state->transferer_chan, state->referred_by,
155 state->exten, state->protocol_id,
156 state->other_session ? state->other_session->channel : NULL,
157 state->params, state->last_response);
158 SCOPE_EXIT_RTN_VALUE(res, "%s: done: %d\n", ast_channel_name(state->transferer_chan), res);
159}
const char * ast_channel_name(const struct ast_channel *chan)
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_ENTER(level,...)
int ast_refer_notify_transfer_request(struct ast_channel *originating_chan, const char *referred_by, const char *exten, const char *protocol_id, struct ast_channel *dest, struct ast_refer_params *params, enum ast_control_transfer state)
Notify a transfer request.
Definition refer.c:541
const char * ast_channel_transfer_state2str(enum ast_control_transfer state)

References ast_channel_name(), ast_channel_transfer_state2str(), ast_refer_notify_transfer_request(), NULL, SCOPE_ENTER, and SCOPE_EXIT_RTN_VALUE.

Referenced by refer_incoming_ari_request(), and refer_progress_notify().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 2214 of file res_pjsip_refer.c.

◆ copy_string()

static char * copy_string ( struct pj_str_t *  str)
static

Definition at line 1518 of file res_pjsip_refer.c.

1519{
1520 int len = pj_strlen(str) + 1;
1521 char *dst = ast_malloc(len);
1522 if (!dst) {
1523 return NULL;
1524 }
1525 ast_copy_pj_str(dst, str, len);
1526 return dst;
1527}
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition res_pjsip.c:2176

References ast_copy_pj_str(), ast_malloc, len(), NULL, and str.

Referenced by add_refer_param(), and refer_incoming_ari_request().

◆ defer_termination_cancel_task()

static int defer_termination_cancel_task ( void *  data)
static

Definition at line 692 of file res_pjsip_refer.c.

693{
694 struct ast_sip_session *session = data;
695
698 ao2_ref(session, -1);
699 return 0;
700}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session)
Cancel a pending deferred termination.
void ast_sip_session_end_if_deferred(struct ast_sip_session *session)
End the session if it had been previously deferred.
A structure describing a SIP session.

References ao2_ref, ast_sip_session_defer_termination_cancel(), ast_sip_session_end_if_deferred(), and session.

Referenced by refer_attended_task().

◆ dlg_releaser_task()

static int dlg_releaser_task ( void *  data)
static

Definition at line 511 of file res_pjsip_refer.c.

511 {
512 pjsip_dlg_dec_session((pjsip_dialog *)data, &refer_progress_module);
513 return 0;
514}
static pjsip_module refer_progress_module
REFER Progress module, used to attach REFER progress structure to subscriptions.

References refer_progress_module.

Referenced by refer_progress_destroy().

◆ get_refer_to_uri()

static pjsip_uri * get_refer_to_uri ( pjsip_tx_data *  tdata)
static

Helper function which returns the name-addr of the Refer-To header or NULL.

Definition at line 1176 of file res_pjsip_refer.c.

1177{
1178 const pj_str_t REFER_TO = { "Refer-To", 8 };
1179 pjsip_generic_string_hdr *refer_to;
1180 pjsip_uri *parsed_uri;
1181
1182 if (!(refer_to = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL))
1183 || !(parsed_uri = pjsip_parse_uri(tdata->pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0))
1184 || (!PJSIP_URI_SCHEME_IS_SIP(parsed_uri) && !PJSIP_URI_SCHEME_IS_SIPS(parsed_uri))) {
1185 return NULL;
1186 }
1187
1188 return parsed_uri;
1189}

References NULL.

Referenced by refer_on_tx_request().

◆ invite_replaces()

static int invite_replaces ( void *  data)
static

Task for invite replaces.

Definition at line 1844 of file res_pjsip_refer.c.

1845{
1846 struct invite_replaces *invite = data;
1847
1848 if (!invite->session->channel) {
1849 return -1;
1850 }
1851
1853 invite->channel = invite->session->channel;
1854
1856 return 0;
1857}
struct ast_bridge * ast_bridge_transfer_acquire_bridge(struct ast_channel *chan)
Acquire the channel's bridge for transfer purposes.
Definition bridge.c:4617
#define ast_channel_ref(c)
Increase channel reference count.
Definition channel.h:3008
struct ast_channel * channel
Structure used to retrieve channel from another session.
struct ast_sip_session * session
Session we want the channel from.
struct ast_channel * channel
Channel from the session (with reference)
struct ast_bridge * bridge
Bridge the channel is in.

References ast_bridge_transfer_acquire_bridge(), ast_channel_ref, invite_replaces::bridge, ast_sip_session::channel, invite_replaces::channel, and invite_replaces::session.

◆ is_refer_var_blocked()

static int is_refer_var_blocked ( const char *  name)
static

Definition at line 1108 of file res_pjsip_refer.c.

1109{
1110 int i;
1111
1112 /* Don't block the Max-Forwards header because the user can override it */
1113 static const char *hdr[] = {
1114 "To",
1115 "From",
1116 "Via",
1117 "Route",
1118 "Contact",
1119 "Call-ID",
1120 "CSeq",
1121 "Allow",
1122 "Content-Length",
1123 "Content-Type",
1124 "Request-URI",
1125 };
1126
1127 for (i = 0; i < ARRAY_LEN(hdr); ++i) {
1128 if (!strcasecmp(name, hdr[i])) {
1129 /* Block addition of this header. */
1130 return 1;
1131 }
1132 }
1133 return 0;
1134}
static const char name[]
Definition format_mp3.c:68
#define ARRAY_LEN(a)
Definition utils.h:706

References ARRAY_LEN, and name.

Referenced by vars_to_headers().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2168 of file res_pjsip_refer.c.

2169{
2170 const pj_str_t str_norefersub = { "norefersub", 10 };
2171
2172 pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint());
2173 pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint());
2174
2175 if (ast_sip_get_norefersub()) {
2176 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub);
2177 }
2178
2181 }
2182
2184 if (!refer_serializer) {
2187 }
2188
2192
2194
2196}
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition res_pjsip.c:2092
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition module.h:478
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
int ast_refer_tech_unregister(const struct ast_refer_tech *tech)
Unregister a refer technology.
Definition refer.c:492
int ast_refer_tech_register(const struct ast_refer_tech *tech)
Register a refer technology.
Definition refer.c:448
unsigned int ast_sip_get_norefersub(void)
Retrieve the global setting 'norefersub'.
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition res_pjsip.c:111
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:518
static pjsip_module refer_out_of_dialog_module
REFER Out-of-dialog module, used to attach session data structure to subscription.
static struct ast_taskprocessor * refer_serializer
static struct ast_sip_session_supplement refer_supplement
static const struct ast_refer_tech refer_tech
#define ast_sip_session_register_supplement(supplement)
struct ast_module * self
Definition module.h:356

References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_module_shutdown_ref, ast_refer_tech_register(), ast_refer_tech_unregister(), ast_sip_create_serializer(), ast_sip_get_norefersub(), ast_sip_get_pjsip_endpoint(), ast_sip_register_service(), ast_sip_session_register_supplement, NULL, refer_out_of_dialog_module, refer_progress_module, refer_serializer, refer_supplement, refer_tech, and ast_module_info::self.

◆ refer_ari_progress_framehook()

static struct ast_frame * refer_ari_progress_framehook ( struct ast_channel chan,
struct ast_frame f,
enum ast_framehook_event  event,
void *  data 
)
static

Progress monitoring frame hook - examines frames to determine state of transfer. Used for the ari-only mode.

Definition at line 389 of file res_pjsip_refer.c.

390{
391 struct refer_progress *progress = data;
392 struct refer_progress_notification *notification = NULL;
393 SCOPE_ENTER(3, "%s\n", ast_channel_name(chan));
394
395 /* We only care about frames *to* the channel */
396 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
397 SCOPE_EXIT_RTN_VALUE(f, "%s: Not EVENT_WRITE\n", ast_channel_name(chan));
398 }
399
400 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
403 && f->datalen >= sizeof(enum ast_control_transfer)) {
405 ast_trace(-1, "%s message: %d\n", ast_channel_name(chan), *message);
406 switch (*message) {
408 notification = refer_progress_notification_alloc(progress, 603, PJSIP_EVSUB_STATE_TERMINATED);
409 break;
411 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
412 break;
414 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
415 break;
417 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
418 break;
420 break;
421 }
422 progress->ari_state->last_response = *message;
423 }
424
425 /* If a notification is due to be sent push it to the taskpool */
426 if (notification) {
427 /* If the subscription is being terminated we don't need the frame hook any longer */
428 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
429 ast_trace(-1, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
430 ast_channel_name(chan));
431 ast_framehook_detach(chan, progress->framehook);
432 }
433
434 /*
435 * If the referer specified "Refer-Sub: false", we can call refer_progress_notify()
436 * directly without pushing a task because it won't be doing any pjproject wotk.
437 * All it will do is send an ARI event.
438 */
439 if (notification->progress->no_refer_sub) {
440 refer_progress_notify(notification);
441 SCOPE_EXIT_RTN_VALUE(f, "%s: done ari no refer sub\n",
442 progress->ari_state ? ast_channel_name(progress->ari_state->transferer_chan) : "????");
443 }
444
445 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
446 ao2_cleanup(notification);
447 }
448 } else {
449 SCOPE_EXIT_RTN_VALUE(f, "%s: Not a transfer event\n", ast_channel_name(chan));
450 }
451
452 SCOPE_EXIT_RTN_VALUE(f, "%s: done\n", ast_channel_name(chan));
453}
#define ao2_cleanup(obj)
Definition astobj2.h:1934
@ AST_FRAMEHOOK_EVENT_WRITE
Definition framehook.h:153
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition framehook.c:177
#define ast_trace(level,...)
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2126
@ AST_TRANSFER_FAILED
@ AST_TRANSFER_UNAVAILABLE
@ AST_TRANSFER_SUCCESS
@ AST_TRANSFER_PROGRESS
@ AST_TRANSFER_INVALID
@ AST_FRAME_CONTROL
@ AST_CONTROL_TRANSFER
static struct refer_progress_notification * refer_progress_notification_alloc(struct refer_progress *progress, int response, pjsip_evsub_state state)
Allocator for REFER Progress notification structure.
static int refer_progress_notify(void *data)
Serialized callback for subscription notification.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@237 data
REFER Progress notification structure.
pjsip_evsub_state state
Subscription state.
struct refer_progress * progress
Refer progress structure to send notification on.
REFER Progress structure.
int no_refer_sub
Refer-Sub: false was specified on the REFER.

References ao2_cleanup, ast_channel_name(), AST_CONTROL_TRANSFER, AST_FRAME_CONTROL, ast_framehook_detach(), AST_FRAMEHOOK_EVENT_WRITE, ast_sip_push_task, ast_trace, AST_TRANSFER_FAILED, AST_TRANSFER_INVALID, AST_TRANSFER_PROGRESS, AST_TRANSFER_SUCCESS, AST_TRANSFER_UNAVAILABLE, ast_frame::data, ast_frame::datalen, ast_frame::frametype, ast_frame_subclass::integer, refer_progress::no_refer_sub, NULL, refer_progress_notification::progress, ast_frame::ptr, refer_progress_notification_alloc(), refer_progress_notify(), SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, refer_progress_notification::state, and ast_frame::subclass.

Referenced by refer_incoming_ari_request().

◆ refer_attended_alloc()

static struct refer_attended * refer_attended_alloc ( struct ast_sip_session transferer,
struct ast_sip_session transferer_second,
struct refer_progress progress 
)
static

Allocator for attended transfer task.

Definition at line 656 of file res_pjsip_refer.c.

659{
660 struct refer_attended *attended;
661
662 attended = ao2_alloc_options(sizeof(*attended), refer_attended_destroy,
664 if (!attended) {
665 return NULL;
666 }
667
668 ao2_ref(transferer, +1);
669 attended->transferer = transferer;
674
675 if (progress) {
676 ao2_ref(progress, +1);
677 attended->progress = progress;
678 }
679
680 return attended;
681}
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
static void refer_attended_destroy(void *obj)
Destructor for attended transfer task.
Structure for attended transfer task.
struct ast_sip_session * transferer
Transferer session.
struct ast_sip_session * transferer_second
Second transferer session.
struct refer_progress * progress
Optional refer progress structure.
struct ast_channel * transferer_chan
Transferer channel.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_ref, ast_channel_ref, ast_sip_session::channel, NULL, refer_attended::progress, refer_attended_destroy(), refer_attended::transferer, refer_attended::transferer_chan, and refer_attended::transferer_second.

Referenced by refer_incoming_attended_request().

◆ refer_attended_destroy()

static void refer_attended_destroy ( void *  obj)
static

Destructor for attended transfer task.

Definition at line 645 of file res_pjsip_refer.c.

646{
647 struct refer_attended *attended = obj;
648
649 ao2_cleanup(attended->transferer);
652 ao2_cleanup(attended->progress);
653}
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition channel.h:3030

References ao2_cleanup, ast_channel_cleanup, refer_attended::progress, refer_attended::transferer, refer_attended::transferer_chan, and refer_attended::transferer_second.

Referenced by refer_attended_alloc().

◆ refer_attended_task()

static int refer_attended_task ( void *  data)
static

Task for attended transfer executed by attended->transferer_second serializer.

Definition at line 734 of file res_pjsip_refer.c.

735{
736 struct refer_attended *attended = data;
737 int response;
738 int (*task_cb)(void *data);
739
740 if (attended->transferer_second->channel) {
741 ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
744
746 attended->transferer_chan,
747 attended->transferer_second->channel));
748
749 ast_debug(3, "Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
752 response);
753 } else {
754 ast_debug(3, "Received REFER request on channel '%s' but other channel has gone.\n",
756 response = 603;
757 }
758
759 if (attended->progress) {
760 struct refer_progress_notification *notification;
761
762 notification = refer_progress_notification_alloc(attended->progress, response,
763 PJSIP_EVSUB_STATE_TERMINATED);
764 if (notification) {
765 if (ast_sip_push_task(attended->progress->serializer, refer_progress_notify, notification)) {
766 ao2_cleanup(notification);
767 }
768 }
769 }
770
771 if (response == 200) {
773 } else {
775 }
777 task_cb, attended->transferer)) {
778 /* Gave the ref to the pushed task. */
779 attended->transferer = NULL;
780 } else {
781 /* Do this anyway even though it is the wrong serializer. */
783 }
784
785 ao2_ref(attended, -1);
786 return 0;
787}
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
Definition bridge.c:4886
#define ast_debug(level,...)
Log a DEBUG message.
static int xfer_response_code2sip(enum ast_transfer_result xfer_code)
static int defer_termination_cancel_task(void *data)
static int session_end_if_deferred_task(void *data)
struct ast_taskprocessor * serializer
int response
SIP response code to send.
struct ast_taskprocessor * serializer
Serializer for notifications.

References ao2_cleanup, ao2_ref, ast_bridge_transfer_attended(), ast_channel_name(), ast_debug, ast_sip_push_task, ast_sip_session_end_if_deferred(), ast_sip_session::channel, defer_termination_cancel_task(), NULL, refer_attended::progress, refer_progress_notification_alloc(), refer_progress_notify(), refer_progress_notification::response, ast_sip_session::serializer, refer_progress::serializer, session_end_if_deferred_task(), refer_attended::transferer, refer_attended::transferer_chan, refer_attended::transferer_second, and xfer_response_code2sip().

Referenced by refer_incoming_attended_request().

◆ refer_blind_callback()

static void refer_blind_callback ( struct ast_channel chan,
struct transfer_channel_data user_data_wrapper,
enum ast_transfer_type  transfer_type 
)
static

Blind transfer callback function.

Definition at line 806 of file res_pjsip_refer.c.

808{
809 struct refer_blind *refer = user_data_wrapper->data;
810 pjsip_generic_string_hdr *referred_by;
811
812 static const pj_str_t str_referred_by = { "Referred-By", 11 };
813 static const pj_str_t str_referred_by_s = { "b", 1 };
814 const char *get_xfrdata;
815
816 pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
817
818 if (refer->progress && !refer->attended && !refer->progress->refer_blind_progress) {
819 /* If blind transfer and endpoint doesn't want to receive all the progress details */
821 PJSIP_EVSUB_STATE_TERMINATED);
822
823 if (notification) {
824 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
825 ao2_cleanup(notification);
826 }
827 }
828 } else if (refer->progress) {
829 /* If attended transfer and progress monitoring is being done attach a frame hook so we can monitor it */
830 struct ast_framehook_interface hook = {
832 .event_cb = refer_progress_framehook,
834 .data = refer->progress,
835 .disable_inheritance = 1,
836 };
837
839 if (!refer->progress->transferee) {
841 PJSIP_EVSUB_STATE_TERMINATED);
842
843 ast_log(LOG_WARNING, "Could not copy channel name '%s' during transfer - assuming success\n",
844 ast_channel_name(chan));
845
846 if (notification) {
847 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
848 ao2_cleanup(notification);
849 }
850 }
851 }
852
853 /* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
854 ao2_ref(user_data_wrapper, +1);
855 refer->progress->transfer_data = user_data_wrapper;
856
857 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
858 ao2_ref(refer->progress, +1);
859
860 /* If we can't attach a frame hook for whatever reason send a notification of success immediately */
861 ast_channel_lock(chan);
862 refer->progress->framehook = ast_framehook_attach(chan, &hook);
863 ast_channel_unlock(chan);
864 if (refer->progress->framehook < 0) {
866 PJSIP_EVSUB_STATE_TERMINATED);
867
868 ast_log(LOG_WARNING, "Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
869 ast_channel_name(chan));
870
871 if (notification) {
872 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
873 ao2_cleanup(notification);
874 }
875 }
876
877 ao2_cleanup(refer->progress);
878 }
879
880 /* We need to bump the reference count for the stasis subscription */
881 ao2_ref(refer->progress, +1);
882 /* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
883 * detect if the transfer target has answered the call
884 */
886 if (!refer->progress->bridge_sub) {
888 PJSIP_EVSUB_STATE_TERMINATED);
889
890 ast_log(LOG_WARNING, "Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success\n",
891 ast_channel_name(chan));
892
893 if (notification) {
894 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
895 ao2_cleanup(notification);
896 }
897 }
898
899 ast_channel_lock(chan);
901 ast_channel_unlock(chan);
902
903 ao2_cleanup(refer->progress);
904 } else {
908 }
909 }
910
911 pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL));
912
913 ast_channel_lock(chan);
914 if ((get_xfrdata = pbx_builtin_getvar_helper(chan, "GET_TRANSFERRER_DATA"))) {
915 get_xfrdata = ast_strdupa(get_xfrdata);
916 }
917 ast_channel_unlock(chan);
918 if (!ast_strlen_zero(get_xfrdata)) {
919 const pjsip_msg * msg = refer->rdata->msg_info.msg;
920 const struct pjsip_hdr *end = &msg->hdr;
921 struct pjsip_hdr *hdr = end->next;
922 struct ast_str *pbxvar = ast_str_create(64); /* initial buffer for variable name, extended on demand */
923 char buf[4096]; /* should be enough for one header value */
924 const char *prefix = get_xfrdata;
925
926 /* The '*' alone matches all headers. */
927 if (!strcmp(prefix, "*")) {
928 prefix = "";
929 }
930 if (pbxvar) {
931 for (; hdr != end; hdr = hdr->next) {
932 if (!pj_strnicmp2(&hdr->name, prefix, strlen(prefix))) {
933 const int hdr_name_strlen = pj_strlen(&hdr->name);
934 const int hdr_name_bytes = hdr_name_strlen + 1; /* +1 for string NULL terminator */
935 char hdr_name[hdr_name_bytes];
936 int len;
937 char *value_str;
938
939 ast_copy_pj_str(hdr_name, &hdr->name, hdr_name_bytes);
940 len = pjsip_hdr_print_on(hdr, buf, sizeof(buf) - 1);
941 if (len < 0) {
942 /* ignore too long headers */
943 ast_log(LOG_WARNING, "Could not store header '%s' from transfer on channel '%s' - too long text\n", hdr_name, ast_channel_name(chan));
944 continue;
945 }
946 buf[len] = '\0';
947
948 /* Get value - remove header name (before ':') from buf and trim blanks. */
949 value_str = strchr(buf, ':');
950 if (!value_str) {
951 /* Ignore header without value */
952 continue;
953 }
954 value_str = ast_strip(value_str + 1); /* +1 to get string right after the ':' delimiter (i.e. header value) */
955
956 ast_str_set(&pbxvar, -1, "~HASH~TRANSFER_DATA~%.*s~", hdr_name_strlen, hdr_name);
957 pbx_builtin_setvar_helper(chan, ast_str_buffer(pbxvar), value_str);
958 ast_debug(5, "On channel '%s' set TRANSFER_DATA variable '%s' to value '%s' \n", ast_channel_name(chan), hdr_name, value_str);
959 }
960 }
961 ast_free(pbxvar);
962 } else {
963 ast_log(LOG_ERROR, "Channel '%s' failed to allocate buffer for TRANSFER_DATA variable\n", ast_channel_name(chan));
964 }
965 }
966
967 referred_by = pjsip_msg_find_hdr_by_names(refer->rdata->msg_info.msg,
968 &str_referred_by, &str_referred_by_s, NULL);
969 if (referred_by) {
970 size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
971 char *uri = ast_alloca(uri_size);
972
973 ast_copy_pj_str(uri, &referred_by->hvalue, uri_size);
974 pbx_builtin_setvar_helper(chan, "__SIPREFERREDBYHDR", S_OR(uri, NULL));
975 } else {
976 pbx_builtin_setvar_helper(chan, "SIPREFERREDBYHDR", NULL);
977 }
978
979 if (refer->replaces) {
980 char replaces[512];
981 char *replaces_val = NULL;
982 int len;
983
984 len = pjsip_hdr_print_on(refer->replaces, replaces, sizeof(replaces) - 1);
985 if (len != -1) {
986 /* pjsip_hdr_print_on does not NULL terminate the buffer */
987 replaces[len] = '\0';
988 replaces_val = replaces + sizeof("Replaces:");
989 }
990 pbx_builtin_setvar_helper(chan, "__SIPREPLACESHDR", replaces_val);
991 } else {
992 pbx_builtin_setvar_helper(chan, "SIPREPLACESHDR", NULL);
993 }
994
995 if (refer->refer_to) {
996 char refer_to[PJSIP_MAX_URL_SIZE];
997
998 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->refer_to, refer_to, sizeof(refer_to));
999 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", S_OR(refer_to, NULL));
1000 } else {
1001 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", NULL);
1002 }
1003}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_log
Definition astobj2.c:42
#define ast_channel_lock(chan)
Definition channel.h:2983
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition channel.h:2984
char * end
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
Definition framehook.c:132
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition framehook.h:227
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
static char prefix[MAX_PREFIX]
Definition http.c:145
#define LOG_ERROR
#define LOG_WARNING
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
static void refer_progress_framehook_destroy(void *data)
Destroy callback for monitoring framehook.
static struct ast_frame * refer_progress_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
Progress monitoring frame hook - examines frames to determine state of transfer.
static void refer_progress_bridge(void *data, struct stasis_subscription *sub, struct stasis_message *message)
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition stasis.c:1101
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition stasis.c:1155
#define stasis_subscribe_pool(topic, callback, data)
Definition stasis.h:680
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
Support for dynamic strings.
Definition strings.h:623
Structure for blind transfer callback details.
pjsip_replaces_hdr * replaces
Optional Replaces header.
pjsip_rx_data * rdata
REFER message.
struct refer_progress * progress
Optional progress structure.
unsigned int attended
Attended transfer flag.
const char * context
Context being used for transfer.
pjsip_sip_uri * refer_to
Optional Refer-To header.
struct transfer_channel_data * transfer_data
Reference to transfer_channel_data related to the refer.
unsigned int refer_blind_progress
Whether to notifies all the progress details on blind transfer.
struct stasis_subscription * bridge_sub
Stasis subscription for bridge events.
char * transferee
Uniqueid of transferee channel.
int framehook
Frame hook for monitoring REFER progress.

References ao2_cleanup, ao2_ref, ast_alloca, ast_bridge_topic_all(), ast_channel_entered_bridge_type(), ast_channel_lock, ast_channel_name(), ast_channel_uniqueid(), ast_channel_unlock, ast_copy_pj_str(), ast_debug, ast_framehook_attach(), ast_framehook_detach(), AST_FRAMEHOOK_INTERFACE_VERSION, ast_free, ast_log, ast_sip_push_task, ast_str_buffer(), ast_str_create, ast_str_set(), ast_strdup, ast_strdupa, ast_strip(), ast_strlen_zero(), refer_blind::attended, refer_progress::bridge_sub, buf, refer_blind::context, transfer_channel_data::data, ast_frame::data, end, refer_progress::framehook, len(), LOG_ERROR, LOG_WARNING, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), prefix, refer_blind::progress, refer_blind::rdata, refer_progress::refer_blind_progress, refer_progress_bridge(), refer_progress_framehook(), refer_progress_framehook_destroy(), refer_progress_notification_alloc(), refer_progress_notify(), refer_blind::refer_to, refer_blind::replaces, S_OR, refer_progress::serializer, stasis_subscribe_pool, stasis_subscription_accept_message_type(), stasis_subscription_change_type(), STASIS_SUBSCRIPTION_FILTER_SELECTIVE, stasis_subscription_set_filter(), refer_progress::transfer_data, refer_progress::transferee, and ast_framehook_interface::version.

Referenced by refer_incoming_attended_request(), and refer_incoming_blind_request().

◆ refer_client_on_evsub_state()

static void refer_client_on_evsub_state ( pjsip_evsub *  sub,
pjsip_event *  event 
)
static

Definition at line 1262 of file res_pjsip_refer.c.

1263{
1264 pjsip_tx_data *tdata;
1265 RAII_VAR(struct ast_sip_endpoint *, endpt, NULL, ao2_cleanup);
1267 int refer_success;
1268 int res = 0;
1269
1270 if (!event) {
1271 return;
1272 }
1273
1274 refer_data = pjsip_evsub_get_mod_data(sub, refer_out_of_dialog_module.id);
1275 if (!refer_data || !refer_data->dlg) {
1276 return;
1277 }
1278
1280
1281 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
1282 /* Check if subscription is suppressed and terminate and send completion code, if so. */
1283 pjsip_rx_data *rdata;
1284 pjsip_generic_string_hdr *refer_sub;
1285 const pj_str_t REFER_SUB = { "Refer-Sub", 9 };
1286
1287 ast_debug(3, "Refer accepted by %s\n", endpt ? ast_sorcery_object_get_id(endpt) : "(unknown endpoint)");
1288
1289 /* Check if response message */
1290 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1291 rdata = event->body.tsx_state.src.rdata;
1292
1293 /* Find Refer-Sub header */
1294 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &REFER_SUB, NULL);
1295
1296 /* Check if subscription is suppressed. If it is, the far end will not terminate it,
1297 * and the subscription will remain active until it times out. Terminating it here
1298 * eliminates the unnecessary timeout.
1299 */
1300 if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
1301 /* Since no subscription is desired, assume that call has been referred successfully
1302 * and terminate subscription.
1303 */
1304 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1305 pjsip_evsub_terminate(sub, PJ_TRUE);
1306 res = -1;
1307 }
1308 }
1309 } else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
1310 pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
1311 /* Check for NOTIFY complete or error. */
1312 pjsip_msg *msg;
1313 pjsip_msg_body *body;
1314 pjsip_status_line status_line = { .code = 0 };
1315 pj_bool_t is_last;
1316 pj_status_t status;
1317
1318 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1319 pjsip_rx_data *rdata;
1320 pj_str_t refer_str;
1321 pj_cstr(&refer_str, "REFER");
1322
1323 rdata = event->body.tsx_state.src.rdata;
1324 msg = rdata->msg_info.msg;
1325
1326 if (msg->type == PJSIP_RESPONSE_MSG
1327 && (event->body.tsx_state.tsx->status_code == 401
1328 || event->body.tsx_state.tsx->status_code == 407)
1329 && pj_stristr(&refer_str, &event->body.tsx_state.tsx->method.name)
1330 && ++refer_data->authentication_challenge_count < MAX_RX_CHALLENGES
1331 && endpt) {
1332
1333 if (!ast_sip_create_request_with_auth(&endpt->outbound_auths,
1334 event->body.tsx_state.src.rdata, event->body.tsx_state.tsx->last_tx, &tdata)) {
1335 /* Send authed REFER */
1337 goto out;
1338 }
1339 }
1340
1341 if (msg->type == PJSIP_REQUEST_MSG) {
1342 if (!pjsip_method_cmp(&msg->line.req.method, pjsip_get_notify_method())) {
1343 body = msg->body;
1344 if (body && !pj_stricmp2(&body->content_type.type, "message")
1345 && !pj_stricmp2(&body->content_type.subtype, "sipfrag")) {
1346 pjsip_parse_status_line((char *)body->data, body->len, &status_line);
1347 }
1348 }
1349 } else {
1350 status_line.code = msg->line.status.code;
1351 status_line.reason = msg->line.status.reason;
1352 }
1353 } else {
1354 status_line.code = 500;
1355 status_line.reason = *pjsip_get_status_text(500);
1356 }
1357
1358 is_last = (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED);
1359 /* If the status code is >= 200, the subscription is finished. */
1360 if (status_line.code >= 200 || is_last) {
1361 res = -1;
1362
1363 refer_success = status_line.code >= 200 && status_line.code < 300;
1364
1365 /* If subscription not terminated and subscription is finished (status code >= 200)
1366 * terminate it */
1367 if (!is_last) {
1368 pjsip_tx_data *tdata;
1369
1370 status = pjsip_evsub_initiate(sub, pjsip_get_subscribe_method(), 0, &tdata);
1371 if (status == PJ_SUCCESS) {
1372 pjsip_evsub_send_request(sub, tdata);
1373 }
1374 }
1375 ast_debug(3, "Refer completed: %d %.*s (%s)\n",
1376 status_line.code,
1377 (int)status_line.reason.slen, status_line.reason.ptr,
1378 refer_success ? "Success" : "Failure");
1379 }
1380 }
1381
1382out:
1383 if (res) {
1385 }
1386}
jack_status_t status
Definition app_jack.c:149
struct ast_sip_endpoint * ast_sip_dialog_get_endpoint(pjsip_dialog *dlg)
Get the endpoint associated with this dialog.
static struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, pjsip_tx_data *tdata, pjsip_tx_data **new_request)
Create a response to an authentication challenge.
Definition res_pjsip.c:208
int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, void *token, void(*callback)(void *token, pjsip_event *e))
General purpose method for sending a SIP request.
Definition res_pjsip.c:1977
#define MAX_RX_CHALLENGES
Definition res_pjsip.h:108
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
An entity with which Asterisk communicates.
Definition res_pjsip.h:1067
FILE * out
Definition utils/frame.c:33
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981

References ao2_cleanup, ast_debug, ast_sip_create_request_with_auth(), ast_sip_dialog_get_endpoint(), ast_sip_send_request(), ast_sorcery_object_get_id(), MAX_RX_CHALLENGES, NULL, out, RAII_VAR, refer_out_of_dialog_module, status, and sub.

Referenced by refer_send().

◆ refer_data_create()

static struct refer_data * refer_data_create ( const struct ast_refer refer)
static

Definition at line 1044 of file res_pjsip_refer.c.

1045{
1046 char *uri_params;
1047 const char *destination;
1049
1050 if (!rdata) {
1051 return NULL;
1052 }
1053
1054 /* typecast to suppress const warning */
1055 rdata->refer = ast_refer_ref((struct ast_refer *) refer);
1057
1058 /* To starts with 'pjsip:' which needs to be removed. */
1059 if (!(destination = strchr(destination, ':'))) {
1060 goto failure;
1061 }
1062 ++destination;/* Now skip the ':' */
1063
1065 if (!rdata->destination) {
1066 goto failure;
1067 }
1068
1070 if (!rdata->from) {
1071 goto failure;
1072 }
1073
1075 if (!rdata->refer_to) {
1076 goto failure;
1077 }
1079
1080 /*
1081 * Sometimes from URI can contain URI parameters, so remove them.
1082 *
1083 * sip:user;user-options@domain;uri-parameters
1084 */
1085 uri_params = strchr(rdata->from, '@');
1086 if (uri_params && (uri_params = strchr(uri_params, ';'))) {
1087 *uri_params = '\0';
1088 }
1089 return rdata;
1090
1091failure:
1092 ao2_cleanup(rdata);
1093 return NULL;
1094}
const char * ast_refer_get_to(const struct ast_refer *refer)
Retrieve the destination of this refer.
Definition refer.c:231
const char * ast_refer_get_from(const struct ast_refer *refer)
Retrieve the source of this refer.
Definition refer.c:226
const char * ast_refer_get_refer_to(const struct ast_refer *refer)
Get the "refer-to" value of a refer.
Definition refer.c:221
struct ast_refer * ast_refer_ref(struct ast_refer *refer)
Bump a refer's ref count.
Definition refer.c:148
int ast_refer_get_to_self(const struct ast_refer *refer)
Retrieve the "to_self" value of this refer.
Definition refer.c:236
static void refer_data_destroy(void *obj)
A refer.
Definition refer.c:59
struct ast_refer * refer

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_cleanup, ast_refer_get_from(), ast_refer_get_refer_to(), ast_refer_get_to(), ast_refer_get_to_self(), ast_refer_ref(), ast_strdup, refer_data::destination, refer_data::from, NULL, refer_data::refer, refer_data_destroy(), refer_data::refer_to, and refer_data::to_self.

Referenced by sip_refer_send().

◆ refer_data_destroy()

static void refer_data_destroy ( void *  obj)
static

Definition at line 1033 of file res_pjsip_refer.c.

1034{
1035 struct refer_data *rdata = obj;
1036
1037 ast_free(rdata->destination);
1038 ast_free(rdata->from);
1039 ast_free(rdata->refer_to);
1040
1041 ast_refer_destroy(rdata->refer);
1042}
struct ast_refer * ast_refer_destroy(struct ast_refer *refer)
Destroy an ast_refer.
Definition refer.c:154

References ast_free, ast_refer_destroy(), refer_data::destination, refer_data::from, refer_data::refer, and refer_data::refer_to.

Referenced by refer_data_create().

◆ refer_incoming_ari_request()

static int refer_incoming_ari_request ( struct ast_sip_session session,
pjsip_rx_data *  rdata,
pjsip_sip_uri *  target,
pjsip_param *  replaces_param,
struct refer_progress progress 
)
static

Definition at line 1553 of file res_pjsip_refer.c.

1555{
1556 int parsed_len;
1557 pjsip_replaces_hdr *replaces;
1558 pjsip_generic_string_hdr *referred_hdr;
1559
1560
1562
1563 struct ast_framehook_interface hook = {
1565 .event_cb = refer_ari_progress_framehook,
1567 .data = progress,
1568 .disable_inheritance = 1,
1569 };
1570
1571 static const pj_str_t str_referred_by = { "Referred-By", 11 };
1572 static const pj_str_t str_referred_by_s = { "b", 1 };
1573 static const pj_str_t str_replaces = { "Replaces", 8 };
1574 SCOPE_ENTER(3, "%s: progress: %p\n", ast_channel_name(session->channel), progress);
1575
1576 if (!progress) {
1577 SCOPE_EXIT_RTN_VALUE(204, "%s: done: %d\n", ast_channel_name(session->channel), 204);
1578 }
1579
1581 if (!state) {
1582 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1583 }
1584
1585 state->last_response = AST_TRANSFER_INVALID;
1586
1587 state->params = ao2_alloc(sizeof(struct ast_refer_params), refer_params_destroy);
1588 if (!state->params) {
1589 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1590 }
1591 AST_VECTOR_INIT(state->params, 0);
1592
1593
1594 ast_channel_ref(session->channel);
1595 state->transferer_chan = session->channel;
1596
1597 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1598 ast_copy_pj_str(state->exten, &target->user, sizeof(state->exten));
1599
1600 /*
1601 * We may want to match in the dialplan without any user
1602 * options getting in the way.
1603 */
1605
1606 referred_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg,
1607 &str_referred_by, &str_referred_by_s, NULL);
1608 if (referred_hdr) {
1609 state->referred_by = copy_string(&referred_hdr->hvalue);
1610 if (!state->referred_by) {
1611 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1612 }
1613 }
1614
1615 if (replaces_param) {
1616 pjsip_dialog *dlg;
1617 pj_str_t replaces_content = { 0, };
1618 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1619
1620 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1621 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1622 pj_strlen(&replaces_content), &parsed_len))) {
1623 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1625 SCOPE_EXIT_RTN_VALUE(400, "%s: done: %d\n", ast_channel_name(session->channel), 400);
1626 }
1627
1628 dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE);
1629 if (dlg) {
1630 state->other_session = ast_sip_dialog_get_session(dlg);
1631 pjsip_dlg_dec_lock(dlg);
1632 }
1633
1634 state->protocol_id = copy_string(&replaces->call_id);
1635 if (!state->protocol_id) {
1636 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1637 }
1638
1639 if (!add_refer_param(state->params, "from", &replaces->from_tag)) {
1640 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1641 }
1642
1643 if (!add_refer_param(state->params, "to", &replaces->to_tag)) {
1644 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1645 }
1646 }
1647
1648 ao2_ref(session, +1);
1649 state->transferer = session;
1650
1651
1652 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
1653 ao2_ref(progress, +1);
1654 ast_channel_lock(session->channel);
1655 progress->framehook = ast_framehook_attach(session->channel, &hook);
1656 ast_channel_unlock(session->channel);
1657
1658 if (progress->framehook < 0) {
1660 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1661 }
1662
1663 if (ari_notify(state)) {
1664 ast_channel_lock(session->channel);
1665 ast_framehook_detach(session->channel, progress->framehook);
1666 progress->framehook = -1;
1668 ast_channel_unlock(session->channel);
1669 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1670 }
1671
1672 /* Transfer ownership to the progress */
1673 progress->ari_state = state;
1674 state = NULL;
1675 SCOPE_EXIT_RTN_VALUE(200, "%s: done: %d\n", ast_channel_name(session->channel), 200);
1676}
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition res_pjsip.h:3561
static void transfer_ari_state_destroy(void *obj)
Destructor of the state used for the ARI transfer.
static void refer_params_destroy(void *obj)
static int ari_notify(struct transfer_ari_state *state)
static struct ast_frame * refer_ari_progress_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
Progress monitoring frame hook - examines frames to determine state of transfer. Used for the ari-onl...
static int add_refer_param(struct ast_refer_params *params, const char *key, struct pj_str_t *str)
struct ast_sip_session * ast_sip_dialog_get_session(pjsip_dialog *dlg)
Retrieves a session from a dialog.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124

References add_refer_param(), ao2_alloc, ao2_cleanup, ao2_ref, ari_notify(), ast_channel_lock, ast_channel_name(), ast_channel_ref, ast_channel_unlock, ast_copy_pj_str(), ast_framehook_attach(), ast_framehook_detach(), AST_FRAMEHOOK_INTERFACE_VERSION, ast_log, ast_sip_dialog_get_session(), AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_sorcery_object_get_id(), AST_TRANSFER_INVALID, AST_VECTOR_INIT, copy_string(), ast_frame::data, LOG_ERROR, NULL, RAII_VAR, refer_ari_progress_framehook(), refer_params_destroy(), refer_progress_framehook_destroy(), SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, transfer_ari_state_destroy(), and ast_framehook_interface::version.

Referenced by refer_incoming_refer_request().

◆ refer_incoming_attended_request()

static int refer_incoming_attended_request ( struct ast_sip_session session,
pjsip_rx_data *  rdata,
pjsip_sip_uri *  target_uri,
pjsip_param *  replaces_param,
struct refer_progress progress 
)
static

Definition at line 1678 of file res_pjsip_refer.c.

1680{
1681 const pj_str_t str_replaces = { "Replaces", 8 };
1682 pj_str_t replaces_content;
1683 pjsip_replaces_hdr *replaces;
1684 int parsed_len;
1685 pjsip_dialog *dlg;
1686 SCOPE_ENTER(3, "%s", ast_channel_name(session->channel));
1687
1688 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1689
1690 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1691 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1692 pj_strlen(&replaces_content), &parsed_len))) {
1693 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1695 SCOPE_EXIT_RTN_VALUE(400, "%s: done: %d\n", ast_channel_name(session->channel), 400);
1696 }
1697
1698 /* See if the dialog is local, or remote */
1699 if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
1700 RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
1701 struct refer_attended *attended;
1702
1703 pjsip_dlg_dec_lock(dlg);
1704
1705 if (!other_session) {
1706 ast_debug(3, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it\n",
1708 SCOPE_EXIT_RTN_VALUE(503, "%s: done: %d\n", ast_channel_name(session->channel), 603);
1709 }
1710
1711 /* We defer actually doing the attended transfer to the other session so no deadlock can occur */
1712 if (!(attended = refer_attended_alloc(session, other_session, progress))) {
1713 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not allocate structure to complete, rejecting\n",
1715 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1716 }
1717
1719 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not defer termination, rejecting\n",
1721 ao2_cleanup(attended);
1722 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1723 }
1724
1725 /* Push it to the other session, which will have both channels with minimal locking */
1726 if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {
1729 ao2_cleanup(attended);
1730 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1731 }
1732
1733 ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
1734 ast_channel_name(session->channel));
1735
1736 SCOPE_EXIT_RTN_VALUE(200, "%s: done: %d\n", ast_channel_name(session->channel), 200);
1737 } else {
1738 const char *context;
1739 struct refer_blind refer = { 0, };
1740 int response;
1741
1743
1744 if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
1745 ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but 'external_replaces' extension not found in context %s\n",
1747 SCOPE_EXIT_RTN_VALUE(404, "%s: done: %d\n", ast_channel_name(session->channel), 404);
1748 }
1749
1750 refer.context = context;
1751 refer.progress = progress;
1752 refer.rdata = rdata;
1753 refer.replaces = replaces;
1754 refer.refer_to = target_uri;
1755 refer.attended = 1;
1756
1758 ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting\n",
1759 ast_channel_name(session->channel),
1761 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1762 }
1763
1765 "external_replaces", context, refer_blind_callback, &refer));
1766
1768 if (response != 200) {
1770 }
1771
1772 SCOPE_EXIT_RTN_VALUE(response, "%s: done: %d\n", ast_channel_name(session->channel), response);
1773 }
1774}
enum ast_transfer_result ast_bridge_transfer_blind(int is_external, struct ast_channel *transferer, const char *exten, const char *context, transfer_channel_cb new_channel_cb, void *user_data)
Blind transfer target to the extension and context provided.
Definition bridge.c:4634
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition pbx.c:2735
#define DETERMINE_TRANSFER_CONTEXT(context, session)
static void refer_blind_callback(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper, enum ast_transfer_type transfer_type)
Blind transfer callback function.
static int refer_attended_task(void *data)
Task for attended transfer executed by attended->transferer_second serializer.
static struct refer_attended * refer_attended_alloc(struct ast_sip_session *transferer, struct ast_sip_session *transferer_second, struct refer_progress *progress)
Allocator for attended transfer task.
int ast_sip_session_defer_termination(struct ast_sip_session *session)
Defer local termination of a session until remote side terminates, or an amount of time passes.

References ao2_cleanup, ast_bridge_transfer_blind(), ast_channel_name(), ast_debug, ast_exists_extension(), ast_log, ast_sip_dialog_get_session(), ast_sip_push_task, ast_sip_session_defer_termination(), ast_sip_session_defer_termination_cancel(), ast_sip_session_end_if_deferred(), ast_sorcery_object_get_id(), refer_blind::attended, refer_blind::context, DETERMINE_TRANSFER_CONTEXT, LOG_ERROR, NULL, refer_blind::progress, RAII_VAR, refer_blind::rdata, refer_attended_alloc(), refer_attended_task(), refer_blind_callback(), refer_blind::refer_to, refer_blind::replaces, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, and xfer_response_code2sip().

Referenced by refer_incoming_refer_request().

◆ refer_incoming_blind_request()

static int refer_incoming_blind_request ( struct ast_sip_session session,
pjsip_rx_data *  rdata,
pjsip_sip_uri *  target,
struct refer_progress progress 
)
static

Definition at line 1776 of file res_pjsip_refer.c.

1778{
1779 const char *context;
1780 char exten[AST_MAX_EXTENSION];
1781 struct refer_blind refer = { 0, };
1782 int response;
1783
1784 /* If no explicit transfer context has been provided use their configured context */
1786
1787 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1788 ast_copy_pj_str(exten, &target->user, sizeof(exten));
1789
1790 /*
1791 * We may want to match in the dialplan without any user
1792 * options getting in the way.
1793 */
1795
1796 /* Uri without exten */
1797 if (ast_strlen_zero(exten)) {
1798 ast_copy_string(exten, "s", sizeof(exten));
1799 ast_debug(3, "Channel '%s' from endpoint '%s' attempted blind transfer to a target without extension. Target was set to 's@%s'\n",
1801 }
1802
1803 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
1804 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
1805 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context);
1806 return 404;
1807 }
1808
1809 refer.context = context;
1810 refer.progress = progress;
1811 refer.rdata = rdata;
1812 refer.refer_to = target;
1813 refer.attended = 0;
1814
1816 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer but could not defer termination, rejecting\n",
1817 ast_channel_name(session->channel),
1819 return 500;
1820 }
1821
1823 exten, context, refer_blind_callback, &refer));
1824
1826 if (response != 200) {
1828 }
1829
1830 return response;
1831}
#define AST_MAX_EXTENSION
Definition channel.h:134
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425

References ast_bridge_transfer_blind(), ast_channel_name(), ast_copy_pj_str(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_log, AST_MAX_EXTENSION, ast_sip_session_defer_termination(), ast_sip_session_defer_termination_cancel(), ast_sip_session_end_if_deferred(), AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_sorcery_object_get_id(), ast_strlen_zero(), refer_blind::attended, refer_blind::context, DETERMINE_TRANSFER_CONTEXT, LOG_ERROR, NULL, refer_blind::progress, refer_blind::rdata, refer_blind_callback(), refer_blind::refer_to, session, and xfer_response_code2sip().

Referenced by refer_incoming_refer_request().

◆ refer_incoming_invite_request()

static int refer_incoming_invite_request ( struct ast_sip_session session,
struct pjsip_rx_data *  rdata 
)
static

Definition at line 1859 of file res_pjsip_refer.c.

1860{
1861 pjsip_dialog *other_dlg = NULL;
1862 pjsip_tx_data *packet;
1863 int response = 0;
1864 RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup);
1865 struct invite_replaces invite;
1866
1867 /* If a Replaces header is present make sure it is valid */
1868 if (pjsip_replaces_verify_request(rdata, &other_dlg, PJ_TRUE, &packet) != PJ_SUCCESS) {
1869 response = packet->msg->line.status.code;
1870 ast_assert(response != 0);
1871 pjsip_tx_data_dec_ref(packet);
1872 goto inv_replace_failed;
1873 }
1874
1875 /* If no other dialog exists then this INVITE request does not have a Replaces header */
1876 if (!other_dlg) {
1877 return 0;
1878 }
1879
1880 other_session = ast_sip_dialog_get_session(other_dlg);
1881 pjsip_dlg_dec_lock(other_dlg);
1882
1883 /* Don't accept an in-dialog INVITE with Replaces as it does not make much sense */
1884 if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
1885 response = 488;
1886 goto inv_replace_failed;
1887 }
1888
1889 if (!other_session) {
1890 ast_debug(3, "INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist\n",
1892 response = 481;
1893 goto inv_replace_failed;
1894 }
1895
1896 invite.session = other_session;
1897
1898 if (ast_sip_push_task_wait_serializer(other_session->serializer, invite_replaces,
1899 &invite)) {
1900 response = 481;
1901 goto inv_replace_failed;
1902 }
1903
1904 ast_channel_lock(session->channel);
1906 ast_channel_unlock(session->channel);
1907 ast_raw_answer(session->channel);
1908
1909 ast_debug(3, "INVITE with Replaces being attempted. '%s' --> '%s'\n",
1910 ast_channel_name(session->channel), ast_channel_name(invite.channel));
1911
1912 /* Unhold the channel now, as later we are not having access to it anymore */
1913 ast_queue_unhold(session->channel);
1915
1916 if (!invite.bridge) {
1917 struct ast_channel *chan = session->channel;
1918
1919 /*
1920 * This will use a synchronous task but we aren't operating in
1921 * the serializer at this point in time, so it won't deadlock.
1922 */
1923 if (!ast_channel_move(invite.channel, chan)) {
1924 /*
1925 * We can't directly use session->channel because ast_channel_move()
1926 * does a masquerade which changes session->channel to a different
1927 * channel. To ensure we work on the right channel we store a
1928 * pointer locally before we begin so it remains valid.
1929 */
1930 ast_hangup(chan);
1931 } else {
1932 response = AST_CAUSE_FAILURE;
1933 }
1934 } else {
1935 if (ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL,
1937 response = AST_CAUSE_FAILURE;
1938 }
1939 }
1940
1941 ast_channel_unref(invite.channel);
1942 ao2_cleanup(invite.bridge);
1943
1944 if (!response) {
1945 /*
1946 * On success we cannot use session->channel in the debug message.
1947 * This thread either no longer has a ref to session->channel or
1948 * session->channel is no longer the original channel.
1949 */
1950 ast_debug(3, "INVITE with Replaces successfully completed.\n");
1951 } else {
1952 ast_debug(3, "INVITE with Replaces failed on channel '%s', hanging up with cause '%d'\n",
1953 ast_channel_name(session->channel), response);
1954 ast_channel_lock(session->channel);
1955 ast_channel_hangupcause_set(session->channel, response);
1956 ast_channel_unlock(session->channel);
1957 ast_hangup(session->channel);
1958 }
1959
1960 return 1;
1961
1962inv_replace_failed:
1963 if (session->inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
1964 ast_debug(3, "INVITE with Replaces failed on channel '%s', sending response of '%d'\n",
1965 ast_channel_name(session->channel), response);
1966 session->defer_terminate = 1;
1967 ast_hangup(session->channel);
1968
1969 if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS
1970 && packet) {
1972 }
1973 } else {
1974 ast_debug(3, "INVITE with Replaces in-dialog on channel '%s', hanging up\n",
1975 ast_channel_name(session->channel));
1976 ast_queue_hangup(session->channel);
1977 }
1978
1979 return 1;
1980}
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
Definition bridge.c:2077
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition bridge.h:600
#define AST_CAUSE_FAILURE
Definition causes.h:150
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2540
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition channel.c:1182
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition channel.c:1171
int ast_channel_move(struct ast_channel *dest, struct ast_channel *source)
Move a channel from its current location to a new location.
Definition channel.c:10846
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition channel.c:1274
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
int ast_raw_answer(struct ast_channel *chan)
Answer a channel.
Definition channel.c:2690
@ AST_STATE_RING
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition channel.c:7422
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Definition res_pjsip.h:2221
struct ast_frame ast_null_frame
Definition main/frame.c:79
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
Main Channel structure associated with a channel.
#define ast_assert(a)
Definition utils.h:779

References ao2_cleanup, ast_assert, ast_bridge_impart(), AST_BRIDGE_IMPART_CHAN_INDEPENDENT, AST_CAUSE_FAILURE, ast_channel_hangupcause_set(), ast_channel_lock, ast_channel_move(), ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_debug, ast_hangup(), ast_null_frame, ast_queue_frame(), ast_queue_hangup(), ast_queue_unhold(), ast_raw_answer(), ast_setstate(), ast_sip_dialog_get_session(), ast_sip_push_task_wait_serializer, ast_sip_session_send_response(), ast_sorcery_object_get_id(), AST_STATE_RING, invite_replaces::bridge, invite_replaces::channel, NULL, RAII_VAR, invite_replaces::session, and session.

Referenced by refer_incoming_request().

◆ refer_incoming_refer_request()

static int refer_incoming_refer_request ( struct ast_sip_session session,
struct pjsip_rx_data *  rdata 
)
static

Definition at line 1982 of file res_pjsip_refer.c.

1983{
1984 pjsip_generic_string_hdr *refer_to;
1985 char *uri;
1986 size_t uri_size;
1987 pjsip_uri *target;
1988 pjsip_sip_uri *target_uri;
1990 pjsip_param *replaces;
1991 int response;
1992
1993 static const pj_str_t str_refer_to = { "Refer-To", 8 };
1994 static const pj_str_t str_refer_to_s = { "r", 1 };
1995 static const pj_str_t str_replaces = { "Replaces", 8 };
1996
1997 SCOPE_ENTER(3, "%s\n", session->channel ? ast_channel_name(session->channel) : "unknown");
1998
1999 if (!session->channel) {
2000 /* No channel to refer. Likely because the call was just hung up. */
2001 pjsip_dlg_respond(session->inv_session->dlg, rdata, 404, NULL, NULL, NULL);
2002 ast_debug(3, "Received a REFER on a session with no channel from endpoint '%s'.\n",
2004 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2005 }
2006
2007 if (!session->endpoint->allowtransfer) {
2008 pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
2009 ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
2011 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2012 }
2013
2014 /* A Refer-To header is required */
2015 refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL);
2016 if (!refer_to) {
2017 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
2018 ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
2020 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2021 }
2022
2023 /* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri
2024 * as pjsip_parse_uri require a NULL terminated uri
2025 */
2026
2027 uri_size = pj_strlen(&refer_to->hvalue) + 1;
2028 uri = ast_alloca(uri_size);
2029 ast_copy_pj_str(uri, &refer_to->hvalue, uri_size);
2030
2031 target = pjsip_parse_uri(rdata->tp_info.pool, uri, uri_size - 1, 0);
2032
2033 if (!target
2034 || (!PJSIP_URI_SCHEME_IS_SIP(target)
2035 && !PJSIP_URI_SCHEME_IS_SIPS(target))) {
2036
2037 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
2038 ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n",
2039 uri, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
2040 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2041 }
2042 target_uri = pjsip_uri_get_uri(target);
2043
2044 /* Set up REFER progress subscription if requested/possible */
2045 if (refer_progress_alloc(session, rdata, &progress)) {
2046 pjsip_dlg_respond(session->inv_session->dlg, rdata, 500, NULL, NULL, NULL);
2047 ast_debug(3, "Could not set up subscription for REFER on channel '%s' from endpoint '%s'\n",
2049 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2050 }
2051
2052 replaces = pjsip_param_find(&target_uri->header_param, &str_replaces);
2053 if (!replaces) {
2054 replaces = pjsip_param_find(&target_uri->other_param, &str_replaces);
2055 }
2056
2057 /* Determine if this is handled externally or an attended or blind transfer */
2058 if (session->transferhandling_ari) {
2059 ast_trace(-1, "%s: incoming ari\n", session->channel ? ast_channel_name(session->channel) : "unknown");
2060 response = refer_incoming_ari_request(session, rdata, target_uri, replaces, progress);
2061 } else if (replaces) {
2062 ast_trace(-1, "%s: incoming attended\n", session->channel ? ast_channel_name(session->channel) : "unknown");
2063 response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
2064 } else {
2065 ast_trace(-1, "%s: incoming blind\n", session->channel ? ast_channel_name(session->channel) : "unknown");
2066 response = refer_incoming_blind_request(session, rdata, target_uri, progress);
2067 }
2068
2069 if (progress->no_refer_sub) {
2070 /* The transferer has requested no subscription, so send a final response immediately */
2071 pjsip_tx_data *tdata;
2072 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
2073 const pj_str_t str_false = { "false", 5 };
2074 pjsip_hdr *hdr;
2075
2076 ast_trace(-1, "%s: No refer sub from endpoint '%s'. Sending reponse %d\n", ast_channel_name(session->channel),
2077 ast_sorcery_object_get_id(session->endpoint), response);
2078
2079 if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, response, NULL, &tdata) != PJ_SUCCESS) {
2080 pjsip_dlg_respond(session->inv_session->dlg, rdata, response, NULL, NULL, NULL);
2081 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2082 }
2083
2084 hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
2085 pjsip_msg_add_hdr(tdata->msg, hdr);
2086
2087 pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2088
2089 } else if (response != 200) {
2090 /* Since this failed we can send a final NOTIFY now and terminate the subscription */
2091 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
2092
2093 if (notification) {
2094 /* The refer_progress_notify function will call ao2_cleanup on this for us */
2095 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
2096 ao2_cleanup(notification);
2097 }
2098 }
2099 }
2100
2101 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2102}
static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target, pjsip_param *replaces_param, struct refer_progress *progress)
static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri, pjsip_param *replaces_param, struct refer_progress *progress)
static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target, struct refer_progress *progress)
static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata, struct refer_progress **progress)
Internal helper function which sets up a refer progress structure if needed.

References ao2_cleanup, ast_alloca, ast_channel_name(), ast_copy_pj_str(), ast_debug, ast_log, ast_sip_push_task, ast_sorcery_object_get_id(), ast_trace, LOG_WARNING, NULL, RAII_VAR, refer_incoming_ari_request(), refer_incoming_attended_request(), refer_incoming_blind_request(), refer_progress_alloc(), refer_progress_notification_alloc(), refer_progress_notify(), refer_progress_notification::response, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, and session.

Referenced by refer_incoming_request().

◆ refer_incoming_request()

static int refer_incoming_request ( struct ast_sip_session session,
pjsip_rx_data *  rdata 
)
static

Definition at line 2104 of file res_pjsip_refer.c.

2105{
2106 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
2108 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_invite_method)) {
2110 } else {
2111 return 0;
2112 }
2113}
static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
static int refer_incoming_refer_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)

References refer_incoming_invite_request(), refer_incoming_refer_request(), and session.

◆ refer_on_tx_request()

static pj_status_t refer_on_tx_request ( pjsip_tx_data *  tdata)
static

Definition at line 1191 of file res_pjsip_refer.c.

1191 {
1192 RAII_VAR(struct ast_str *, refer_to_str, ast_str_create(PJSIP_MAX_URL_SIZE), ast_free_ptr);
1193 const pj_str_t REFER_TO = { "Refer-To", 8 };
1194 pjsip_generic_string_hdr *refer_to_hdr;
1195 pjsip_dialog *dlg;
1196 struct refer_data *refer_data;
1197 pjsip_uri *parsed_uri;
1198 pjsip_sip_uri *refer_to_uri;
1199
1200 /*
1201 * If this is a request in response to a 401/407 Unauthorized challenge, the
1202 * Refer-To URI has been rewritten already, so don't attempt to re-write it again.
1203 * Checking for presence of the Authorization header is not an ideal solution. We do this because
1204 * there exists some race condition where this dialog is not the same as the one used
1205 * to send the original request in which case we don't have the correct refer_data.
1206 */
1207 if (!refer_to_str
1208 || pjsip_msg_find_hdr(tdata->msg, PJSIP_H_AUTHORIZATION, NULL)
1209 || !(dlg = pjsip_tdata_get_dlg(tdata))
1210 || !(refer_data = pjsip_dlg_get_mod_data(dlg, refer_out_of_dialog_module.id))
1211 || !refer_data->to_self
1212 || !(parsed_uri = get_refer_to_uri(tdata))) {
1213 goto out;
1214 }
1215 refer_to_uri = pjsip_uri_get_uri(parsed_uri);
1216 ast_sip_rewrite_uri_to_local(refer_to_uri, tdata);
1217
1218 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, parsed_uri, ast_str_buffer(refer_to_str), ast_str_size(refer_to_str));
1219 refer_to_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL);
1220 pj_strdup2(tdata->pool, &refer_to_hdr->hvalue, ast_str_buffer(refer_to_str));
1221
1222out:
1223 return PJ_SUCCESS;
1224}
void ast_free_ptr(void *ptr)
free() wrapper
Definition astmm.c:1739
int ast_sip_rewrite_uri_to_local(pjsip_sip_uri *uri, pjsip_tx_data *tdata)
Replace domain and port of SIP URI to point to (external) signaling address of this Asterisk instance...
Definition res_pjsip.c:603
static pjsip_uri * get_refer_to_uri(pjsip_tx_data *tdata)
Helper function which returns the name-addr of the Refer-To header or NULL.
size_t attribute_pure ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition strings.h:742

References ast_free_ptr(), ast_sip_rewrite_uri_to_local(), ast_str_buffer(), ast_str_create, ast_str_size(), get_refer_to_uri(), NULL, out, RAII_VAR, refer_out_of_dialog_module, and refer_data::to_self.

◆ refer_out_of_dialog_destroy()

static void refer_out_of_dialog_destroy ( void *  obj)
static

Destructor for REFER out of dialog structure.

Definition at line 1243 of file res_pjsip_refer.c.

1243 {
1244 struct refer_out_of_dialog *data = obj;
1245
1246 if (data->dlg) {
1247 /* ast_sip_push_task_wait_servant should not be called in a destructor,
1248 * however in this case it seems to be fine.
1249 */
1251 }
1252}
#define ast_sip_push_task_wait_servant(serializer, sip_task, task_data)
Definition res_pjsip.h:2165
static int refer_unreference_dialog(void *obj)

References ast_sip_push_task_wait_servant, refer_out_of_dialog::dlg, refer_serializer, and refer_unreference_dialog().

Referenced by refer_send().

◆ refer_outgoing_request()

static void refer_outgoing_request ( struct ast_sip_session session,
struct pjsip_tx_data *  tdata 
)
static

Definition at line 2148 of file res_pjsip_refer.c.

2149{
2150 if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method)
2151 || !session->channel
2152 || session->inv_session->state != PJSIP_INV_STATE_NULL) {
2153 return;
2154 }
2155
2156 ast_channel_lock(session->channel);
2157 add_header_from_channel_var(session->channel, "SIPREPLACESHDR", "Replaces", tdata);
2158 add_header_from_channel_var(session->channel, "SIPREFERREDBYHDR", "Referred-By", tdata);
2159 ast_channel_unlock(session->channel);
2160}
static void add_header_from_channel_var(struct ast_channel *chan, const char *var_name, const char *header_name, pjsip_tx_data *tdata)
Use the value of a channel variable as the value of a SIP header.

References add_header_from_channel_var(), ast_channel_lock, ast_channel_unlock, and session.

◆ refer_params_destroy()

static void refer_params_destroy ( void *  obj)
static

Definition at line 127 of file res_pjsip_refer.c.

128{
129 struct ast_refer_params *params = obj;
130
131 for (int i = 0; i < AST_VECTOR_SIZE(params); ++i) {
132 struct ast_refer_param param = AST_VECTOR_GET(params, i);
133 ast_free((char *) param.param_name);
134 ast_free((char *) param.param_value);
135 }
136}
const char * param_value
Definition refer.h:83
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708

References ast_free, AST_VECTOR_GET, AST_VECTOR_SIZE, ast_refer_param::param_name, and ast_refer_param::param_value.

Referenced by refer_incoming_ari_request().

◆ refer_progress_alloc()

static int refer_progress_alloc ( struct ast_sip_session session,
pjsip_rx_data *  rdata,
struct refer_progress **  progress 
)
static

Internal helper function which sets up a refer progress structure if needed.

Definition at line 553 of file res_pjsip_refer.c.

554{
555 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
556 pjsip_generic_string_hdr *refer_sub = NULL;
557 const pj_str_t str_true = { "true", 4 };
558 pjsip_hdr hdr_list;
559 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
560 int no_refer_sub = 0;
561 SCOPE_ENTER(3, "%s\n", ast_channel_name(session->channel));
562
563 *progress = NULL;
564
565 /* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */
566 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
567 if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4))) {
568 no_refer_sub = 1;
569 }
570
571 if (!(*progress = ao2_alloc(sizeof(struct refer_progress), refer_progress_destroy))) {
572 SCOPE_EXIT_RTN_VALUE(-1, "%s: done: %d\n", ast_channel_name(session->channel), -1);
573 }
574
575 (*progress)->no_refer_sub = no_refer_sub;
576
577 ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
579
580 (*progress)->refer_blind_progress = session->endpoint->refer_blind_progress;
581
582 (*progress)->framehook = -1;
583
584 /* Create name with seq number appended. */
585 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/refer/%s",
587
588 if (!((*progress)->serializer = ast_sip_create_serializer(tps_name))) {
589 goto error;
590 }
591
592 /*
593 * If the referer request the subscription be suppressed, we can stop here.
594 */
595 if ((*progress)->no_refer_sub) {
596 SCOPE_EXIT_RTN_VALUE(0, "%s: done no refer sub: %d\n", ast_channel_name(session->channel), 0);
597 }
598
599 /* Create the implicit subscription for monitoring of this transfer */
600 if (pjsip_xfer_create_uas(session->inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
601 goto error;
602 }
603
604 /* To prevent a potential deadlock we need the dialog so we can lock/unlock */
605 (*progress)->dlg = session->inv_session->dlg;
606 /* We also need to make sure it stays around until we're done with it */
607 pjsip_dlg_inc_session((*progress)->dlg, &refer_progress_module);
608
609 /* Associate the REFER progress structure with the subscription */
610 ao2_ref(*progress, +1);
611 pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
612
613 pj_list_init(&hdr_list);
614 if (refer_sub) {
615 pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->inv_session->dlg->pool, &str_refer_sub, &str_true);
616
617 pj_list_push_back(&hdr_list, hdr);
618 }
619
620 /* Accept the REFER request */
621 ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress);
622 pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
623
624 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
625
626error:
628 *progress = NULL;
629 SCOPE_EXIT_RTN_VALUE(-1, "%s: done: %d\n", ast_channel_name(session->channel), -1);
630}
static void refer_progress_destroy(void *obj)
Destructor for REFER progress sutrcture.
static pjsip_evsub_user refer_progress_evsub_cb
Callback structure for subscription.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
int error(const char *format,...)

References ao2_alloc, ao2_cleanup, ao2_ref, ast_channel_name(), ast_debug, ast_sip_create_serializer(), ast_sorcery_object_get_id(), ast_taskprocessor_build_name(), AST_TASKPROCESSOR_MAX_NAME, error(), refer_progress::no_refer_sub, NULL, refer_progress::rdata, refer_progress_destroy(), refer_progress_evsub_cb, refer_progress_module, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, and session.

Referenced by refer_incoming_refer_request().

◆ refer_progress_bridge()

static void refer_progress_bridge ( void *  data,
struct stasis_subscription sub,
struct stasis_message message 
)
static

Definition at line 272 of file res_pjsip_refer.c.

274{
275 struct refer_progress *progress = data;
276 struct ast_bridge_blob *enter_blob;
277 struct refer_progress_notification *notification;
278 struct ast_channel *chan;
279
281 ao2_ref(progress, -1);
282 return;
283 }
284
286 /* Don't care */
287 return;
288 }
289
290 enter_blob = stasis_message_data(message);
291 if (strcmp(enter_blob->channel->base->uniqueid, progress->transferee)) {
292 /* Don't care */
293 return;
294 }
295
296 if (!progress->transfer_data->completed) {
297 /* We can't act on this message because the transfer_channel_data doesn't show that
298 * the transfer is ready to progress */
299 return;
300 }
301
302 /* OMG the transferee is joining a bridge. His call got answered! */
303 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
304 if (notification) {
305 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
306 ao2_cleanup(notification);
307 }
308 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
309 }
310
311 chan = ast_channel_get_by_name(progress->transferee);
312 if (!chan) {
313 /* The channel is already gone */
314 return;
315 }
316
317 ast_channel_lock(chan);
318 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as it has joined a bridge\n",
319 ast_channel_name(chan));
320 ast_framehook_detach(chan, progress->framehook);
321 ast_channel_unlock(chan);
322
323 ast_channel_unref(chan);
324}
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1417
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition stasis.c:1252
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition stasis.c:1049
Blob of data associated with a bridge.
struct ast_channel_snapshot * channel
const ast_string_field uniqueid
struct ast_channel_snapshot_base * base

References ao2_cleanup, ao2_ref, ast_channel_entered_bridge_type(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_debug, ast_framehook_detach(), ast_sip_push_task, ast_channel_snapshot::base, ast_bridge_blob::channel, refer_progress_notification_alloc(), refer_progress_notify(), stasis_message_data(), stasis_subscription_final_message(), stasis_unsubscribe(), sub, and ast_channel_snapshot_base::uniqueid.

Referenced by refer_blind_callback().

◆ refer_progress_destroy()

static void refer_progress_destroy ( void *  obj)
static

Destructor for REFER progress sutrcture.

Definition at line 517 of file res_pjsip_refer.c.

518{
519 struct refer_progress *progress = obj;
520 SCOPE_ENTER(3, "%p\n", progress);
521
522 if (progress->bridge_sub) {
523 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
524 }
525
526 if (progress->dlg) {
527 /*
528 * Although the dlg session count was incremented in a pjsip servant
529 * thread, there's no guarantee that the last thread to unref this progress
530 * object was one. Before we decrement, we need to make sure that this
531 * is either a servant thread or that we push the decrement to a
532 * serializer that is one.
533 *
534 * Because pjsip_dlg_dec_session requires the dialog lock, we don't want
535 * to wait on the task to complete if we had to push it to a serializer.
536 */
538 pjsip_dlg_dec_session(progress->dlg, &refer_progress_module);
539 } else {
541 }
542 }
543
544 ao2_cleanup(progress->transfer_data);
545 ao2_cleanup(progress->ari_state);
546
547 ast_free(progress->transferee);
549 SCOPE_EXIT_RTN("%p\n", progress);
550}
#define SCOPE_EXIT_RTN(...)
int ast_sip_thread_is_servant(void)
Determine if the current thread is a SIP servant thread.
Definition res_pjsip.c:2285
static int dlg_releaser_task(void *data)
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.

References ao2_cleanup, ast_free, ast_sip_push_task, ast_sip_thread_is_servant(), ast_taskprocessor_unreference(), dlg_releaser_task(), NULL, refer_progress_module, SCOPE_ENTER, SCOPE_EXIT_RTN, and stasis_unsubscribe().

Referenced by refer_progress_alloc().

◆ refer_progress_framehook()

static struct ast_frame * refer_progress_framehook ( struct ast_channel chan,
struct ast_frame f,
enum ast_framehook_event  event,
void *  data 
)
static

Progress monitoring frame hook - examines frames to determine state of transfer.

Definition at line 327 of file res_pjsip_refer.c.

329{
330 struct refer_progress *progress = data;
331 struct refer_progress_notification *notification = NULL;
332
333 /* We only care about frames *to* the channel */
334 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
335 return f;
336 }
337
338 /* If the completed flag hasn't been raised, skip this pass. */
339 if (!progress->transfer_data->completed) {
340 return f;
341 }
342
343 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
344 if (f->frametype == AST_FRAME_VOICE && !progress->subclass) {
345 /* Media is passing without progress, this means the call has been answered */
346 progress->subclass = AST_CONTROL_ANSWER;
347 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
348 } else if (f->frametype == AST_FRAME_CONTROL) {
349 /* Based on the control frame being written we can send a NOTIFY advising of the progress */
351 /* Don't set progress->subclass; an ANSWER can still follow */
352 notification = refer_progress_notification_alloc(progress, 180, PJSIP_EVSUB_STATE_ACTIVE);
353 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
354 progress->subclass = f->subclass.integer;
355 notification = refer_progress_notification_alloc(progress, 486, PJSIP_EVSUB_STATE_TERMINATED);
356 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
357 progress->subclass = f->subclass.integer;
358 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
359 } else if (f->subclass.integer == AST_CONTROL_PROGRESS) {
360 /* Don't set progress->subclass; an ANSWER can still follow */
361 notification = refer_progress_notification_alloc(progress, 183, PJSIP_EVSUB_STATE_ACTIVE);
362 } else if (f->subclass.integer == AST_CONTROL_PROCEEDING) {
363 /* Don't set progress->subclass; an ANSWER can still follow */
364 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
365 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
366 progress->subclass = f->subclass.integer;
367 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
368 }
369 }
370
371 /* If a notification is due to be sent push it to the taskpool */
372 if (notification) {
373 /* If the subscription is being terminated we don't need the frame hook any longer */
374 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
375 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
376 ast_channel_name(chan));
377 ast_framehook_detach(chan, progress->framehook);
378 }
379
380 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
381 ao2_cleanup(notification);
382 }
383 }
384
385 return f;
386}
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_PROCEEDING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING

References ao2_cleanup, ast_channel_name(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RING, AST_CONTROL_RINGING, ast_debug, AST_FRAME_CONTROL, AST_FRAME_VOICE, ast_framehook_detach(), AST_FRAMEHOOK_EVENT_WRITE, ast_sip_push_task, ast_frame::frametype, ast_frame_subclass::integer, NULL, refer_progress_notification_alloc(), refer_progress_notify(), refer_progress_notification::state, and ast_frame::subclass.

Referenced by refer_blind_callback().

◆ refer_progress_framehook_destroy()

static void refer_progress_framehook_destroy ( void *  data)
static

Destroy callback for monitoring framehook.

Definition at line 456 of file res_pjsip_refer.c.

457{
458 struct refer_progress *progress = data;
459 struct refer_progress_notification *notification = NULL;
460 SCOPE_ENTER(3, "%p\n", progress);
461
462 /*
463 * If the referer didn't request the subscription be suppressed, we need to do
464 * a final notification.
465 */
466 if (!progress->no_refer_sub) {
467 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
468 if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
469 ao2_cleanup(notification);
470 }
471 }
472
473 if (progress->bridge_sub) {
474 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
475 }
476
478 SCOPE_EXIT_RTN("%p\n", progress);
479}

References ao2_cleanup, ast_sip_push_task, NULL, refer_progress_notification_alloc(), refer_progress_notify(), SCOPE_ENTER, SCOPE_EXIT_RTN, and stasis_unsubscribe().

Referenced by refer_blind_callback(), and refer_incoming_ari_request().

◆ refer_progress_notification_alloc()

static struct refer_progress_notification * refer_progress_notification_alloc ( struct refer_progress progress,
int  response,
pjsip_evsub_state  state 
)
static

Allocator for REFER Progress notification structure.

Definition at line 162 of file res_pjsip_refer.c.

164{
165 struct refer_progress_notification *notification = ao2_alloc(sizeof(*notification), refer_progress_notification_destroy);
166
167 if (!notification) {
168 return NULL;
169 }
170
171 ao2_ref(progress, +1);
172 notification->progress = progress;
173 notification->response = response;
174 notification->state = state;
175
176 return notification;
177}
static void refer_progress_notification_destroy(void *obj)
Destructor for REFER Progress notification structure.

References ao2_alloc, ao2_ref, NULL, refer_progress_notification::progress, refer_progress_notification_destroy(), refer_progress_notification::response, and refer_progress_notification::state.

Referenced by refer_ari_progress_framehook(), refer_attended_task(), refer_blind_callback(), refer_incoming_refer_request(), refer_progress_bridge(), refer_progress_framehook(), and refer_progress_framehook_destroy().

◆ refer_progress_notification_destroy()

static void refer_progress_notification_destroy ( void *  obj)
static

Destructor for REFER Progress notification structure.

Definition at line 139 of file res_pjsip_refer.c.

140{
141 struct refer_progress_notification *notification = obj;
142 SCOPE_ENTER(3, "%p\n", obj);
143
144 ao2_cleanup(notification->progress);
145 SCOPE_EXIT_RTN("%p\n", obj);
146}

References ao2_cleanup, refer_progress_notification::progress, SCOPE_ENTER, and SCOPE_EXIT_RTN.

Referenced by refer_progress_notification_alloc().

◆ refer_progress_notify()

static int refer_progress_notify ( void *  data)
static

Serialized callback for subscription notification.

Locking and serialization:

Although refer_progress_notify() always runs in the progress serializer, the pjproject evsub module itself can cause the subscription to be destroyed which then triggers refer_progress_on_evsub_state() to clean it up. In this case, it's possible that refer_progress_notify() could get the subscription pulled out from under it while it's trying to use it.

At one point we tried to have refer_progress_on_evsub_state() push the cleanup to the serializer and wait for its return before returning to pjproject but since pjproject calls its state callbacks with the dialog locked, this required us to unlock the dialog while waiting for the serialized cleanup, then lock it again before returning to pjproject. There were also still some cases where other callers of refer_progress_notify() weren't using the serializer and crashes were resulting.

Although all callers of refer_progress_notify() now use the progress serializer, we decided to simplify the locking so we didn't have to unlock and relock the dialog in refer_progress_on_evsub_state().

Now, refer_progress_notify() holds the dialog lock for all its work rather than just when calling pjsip_evsub_set_mod_data() to clear the module data. Since pjproject also holds the dialog lock while calling refer_progress_on_evsub_state(), there should be no more chances for the subscription to be cleaned up while still being used to send NOTIFYs.

Definition at line 208 of file res_pjsip_refer.c.

209{
210 RAII_VAR(struct refer_progress_notification *, notification, data, ao2_cleanup);
211 struct transfer_ari_state *ari_state = notification->progress->ari_state;
212 pjsip_evsub *sub;
213 pjsip_tx_data *tdata;
214 SCOPE_ENTER(3, "%s: no_refer_sub: %s\n",
215 ari_state ? ast_channel_name(ari_state->transferer_chan) : "????",
216 AST_YESNO(notification->progress->no_refer_sub));
217
218 /*
219 * If the referer included a "Refer-Sub: false" header, we don't want to
220 * create the automatic subscription but, if the transfer is being controlled
221 * by ARI, we still want the app to get the progress events.
222 */
223 if (notification->progress->no_refer_sub) {
224 if (ari_state) {
225 ari_notify(ari_state);
226 }
227 SCOPE_EXIT_RTN_VALUE(0, "%s: done\n",
228 ari_state ? ast_channel_name(ari_state->transferer_chan) : "????");
229 }
230
231 pjsip_dlg_inc_lock(notification->progress->dlg);
232
233 /* If the subscription has already been terminated we can't send a notification */
234 if (!(sub = notification->progress->sub)) {
235 ast_debug(3, "Not sending NOTIFY of response '%d' and state '%u' on progress monitor '%p' as subscription has been terminated\n",
236 notification->response, notification->state, notification->progress);
237 pjsip_dlg_dec_lock(notification->progress->dlg);
238 SCOPE_EXIT_RTN_VALUE(0, "???\n");
239 }
240
241 /* Send a deferred initial 100 Trying SIP frag NOTIFY if we haven't already. */
242 if (!notification->progress->sent_100) {
243 notification->progress->sent_100 = 1;
244 if (notification->response != 100) {
245 ast_debug(3, "Sending initial 100 Trying NOTIFY for progress monitor '%p'\n",
246 notification->progress);
247 if (pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) {
248 pjsip_xfer_send_request(sub, tdata);
249 }
250 }
251 }
252
253 ast_debug(3, "Sending NOTIFY with response '%d' and state '%u' on subscription '%p' and progress monitor '%p'\n",
254 notification->response, notification->state, sub, notification->progress);
255
256 /* Actually send the notification */
257 if (pjsip_xfer_notify(sub, notification->state, notification->response, NULL, &tdata) == PJ_SUCCESS) {
258 pjsip_xfer_send_request(sub, tdata);
259 }
260
261
262 if (notification->progress->ari_state) {
263 struct transfer_ari_state *ari_state = notification->progress->ari_state;
264 ari_notify(ari_state);
265 }
266
267 pjsip_dlg_dec_lock(notification->progress->dlg);
268
269 SCOPE_EXIT_RTN_VALUE(0, "???\n");
270}
#define AST_YESNO(x)
return Yes or No depending on the argument.
Definition strings.h:143
struct ast_channel * transferer_chan

References ao2_cleanup, ari_notify(), ast_channel_name(), ast_debug, AST_YESNO, NULL, RAII_VAR, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, sub, and transfer_ari_state::transferer_chan.

Referenced by refer_ari_progress_framehook(), refer_attended_task(), refer_blind_callback(), refer_incoming_refer_request(), refer_progress_bridge(), refer_progress_framehook(), and refer_progress_framehook_destroy().

◆ refer_progress_on_evsub_state()

static void refer_progress_on_evsub_state ( pjsip_evsub *  sub,
pjsip_event *  event 
)
static

Callback for REFER subscription state changes.

See also
refer_progress_notify

The documentation attached to refer_progress_notify has more information about the locking issues with cleaning up the subscription.

Note
pjproject holds the dialog lock while calling this function.

Definition at line 491 of file res_pjsip_refer.c.

492{
493 struct refer_progress *progress = pjsip_evsub_get_mod_data(sub, refer_progress_module.id);
494
495 /*
496 * If being destroyed, remove the progress object from the subscription
497 * and release the reference it had.
498 */
499 if (progress && (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)) {
500 pjsip_evsub_set_mod_data(progress->sub, refer_progress_module.id, NULL);
501 progress->sub = NULL;
503 }
504}

References ao2_cleanup, NULL, refer_progress_module, and sub.

◆ refer_send()

static int refer_send ( void *  data)
static

Definition at line 1396 of file res_pjsip_refer.c.

1397{
1398 struct refer_data *rdata = data; /* The caller holds a reference */
1399 pjsip_tx_data *tdata;
1400 pjsip_evsub *sub;
1401 pj_str_t tmp;
1402 char refer_to_str[PJSIP_MAX_URL_SIZE];
1403 char disp_name_escaped[128];
1404 struct refer_out_of_dialog *refer;
1405 struct pjsip_evsub_user xfer_cb;
1406 RAII_VAR(char *, uri, NULL, ast_free);
1407 RAII_VAR(char *, tmp_str, NULL, ast_free);
1408 RAII_VAR(char *, display_name, NULL, ast_free);
1409 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1410 RAII_VAR(struct ast_sip_endpoint *, refer_to_endpoint, NULL, ao2_cleanup);
1411
1412 endpoint = ast_sip_get_endpoint(rdata->destination, 1, &uri);
1413 if (!endpoint) {
1415 "PJSIP REFER - Could not find endpoint '%s' and no default outbound endpoint configured\n",
1416 rdata->destination);
1417 return -1;
1418 }
1419 ast_debug(3, "Request URI: %s\n", uri);
1420
1421 refer_to_endpoint = ast_sip_get_endpoint(rdata->refer_to, 0, &tmp_str);
1422 if (!tmp_str) {
1423 ast_log(LOG_WARNING, "PJSIP REFER - Refer to not a valid resource identifier or SIP URI\n");
1424 return -1;
1425 }
1426 if (!(refer = ao2_alloc(sizeof(struct refer_out_of_dialog), refer_out_of_dialog_destroy))) {
1427 ast_log(LOG_ERROR, "PJSIP REFER - Could not allocate resources.\n");
1428 return -1;
1429 }
1430 /* The dialog will be terminated in the subscription event callback
1431 * when the subscription has terminated. */
1433 refer->dlg = ast_sip_create_dialog_uac(endpoint, uri, NULL);
1434 if (!refer->dlg) {
1435 ast_log(LOG_WARNING, "PJSIP REFER - Could not create dialog\n");
1436 ao2_cleanup(refer);
1437 return -1;
1438 }
1439 ast_sip_dialog_set_endpoint(refer->dlg, endpoint);
1440
1441 pj_bzero(&xfer_cb, sizeof(xfer_cb));
1442 xfer_cb.on_evsub_state = &refer_client_on_evsub_state;
1443 if (pjsip_xfer_create_uac(refer->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
1444 ast_log(LOG_WARNING, "PJSIP REFER - Could not create uac\n");
1445 ao2_cleanup(refer);
1446 return -1;
1447 }
1448
1449 display_name = ast_refer_get_var_and_unlink(rdata->refer, "display_name");
1450 if (display_name) {
1451 ast_escape_quoted(display_name, disp_name_escaped, sizeof(disp_name_escaped));
1452 snprintf(refer_to_str, sizeof(refer_to_str), "\"%s\" <%s>", disp_name_escaped, tmp_str);
1453 } else {
1454 snprintf(refer_to_str, sizeof(refer_to_str), "%s", tmp_str);
1455 }
1456
1457 /* refer_out_of_dialog_module requires a reference to dlg
1458 * which will be released in refer_client_on_evsub_state()
1459 * when the implicit REFER subscription terminates */
1460 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, refer);
1461 if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, refer_to_str), &tdata) != PJ_SUCCESS) {
1462 ast_log(LOG_WARNING, "PJSIP REFER - Could not create request\n");
1463 goto failure;
1464 }
1465
1466 if (refer_to_endpoint && rdata->to_self) {
1467 pjsip_dlg_add_usage(refer->dlg, &refer_out_of_dialog_module, rdata);
1468 }
1469
1470 ast_sip_update_to_uri(tdata, uri);
1471 ast_sip_update_from(tdata, rdata->from);
1472
1473 /*
1474 * This copies any headers found in the refer's variables to
1475 * tdata.
1476 */
1477 vars_to_headers(rdata->refer, tdata);
1478 ast_debug(1, "Sending REFER to '%s' (via endpoint %s) from '%s'\n",
1479 rdata->destination, ast_sorcery_object_get_id(endpoint), rdata->from);
1480
1481 if (pjsip_xfer_send_request(sub, tdata) == PJ_SUCCESS) {
1482 return 0;
1483 }
1484
1485failure:
1486 ao2_cleanup(refer);
1487 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1488 pjsip_evsub_terminate(sub, PJ_FALSE);
1489 return -1;
1490}
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
char * ast_refer_get_var_and_unlink(struct ast_refer *refer, const char *name)
Get the specified variable on the refer and unlink it from the container of variables.
Definition refer.c:269
struct ast_sip_endpoint * ast_sip_get_endpoint(const char *to, int get_default_outbound, char **uri)
Retrieves an endpoint and URI from the "to" string.
Definition res_pjsip.c:3224
pjsip_dialog * ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user)
General purpose method for creating a UAC dialog with an endpoint.
Definition res_pjsip.c:962
int ast_sip_update_from(pjsip_tx_data *tdata, char *from)
Overwrite fields in the outbound 'From' header.
Definition res_pjsip.c:3358
int ast_sip_update_to_uri(pjsip_tx_data *tdata, const char *to)
Replace the To URI in the tdata with the supplied one.
Definition res_pjsip.c:3298
static void refer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
static enum pjsip_status_code vars_to_headers(const struct ast_refer *refer, pjsip_tx_data *tdata)
static void refer_out_of_dialog_destroy(void *obj)
Destructor for REFER out of dialog structure.
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
Definition utils.c:815

References ao2_alloc, ao2_cleanup, ast_debug, ast_escape_quoted(), ast_free, ast_log, ast_refer_get_var_and_unlink(), ast_sip_create_dialog_uac(), ast_sip_dialog_set_endpoint(), ast_sip_get_endpoint(), ast_sip_update_from(), ast_sip_update_to_uri(), ast_sorcery_object_get_id(), refer_out_of_dialog::authentication_challenge_count, refer_data::destination, refer_out_of_dialog::dlg, refer_data::from, LOG_ERROR, LOG_WARNING, NULL, RAII_VAR, refer_data::refer, refer_client_on_evsub_state(), refer_out_of_dialog_destroy(), refer_out_of_dialog_module, refer_data::refer_to, sub, refer_data::to_self, and vars_to_headers().

Referenced by sip_refer_send().

◆ refer_unreference_dialog()

static int refer_unreference_dialog ( void *  obj)
static

Definition at line 1226 of file res_pjsip_refer.c.

1227{
1228 struct refer_out_of_dialog *data = obj;
1229
1230 /* This is why we keep the dialog on the subscription. When the subscription
1231 * is destroyed, there is no guarantee that the underlying dialog is ready
1232 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1233 * either. The dialog could be destroyed before our subscription is. We fix
1234 * this problem by keeping a reference to the dialog until it is time to
1235 * destroy the subscription.
1236 */
1237 pjsip_dlg_dec_session(data->dlg, &refer_out_of_dialog_module);
1238 data->dlg = NULL;
1239
1240 return 0;
1241}

References refer_out_of_dialog::dlg, NULL, and refer_out_of_dialog_module.

Referenced by refer_out_of_dialog_destroy().

◆ session_end_if_deferred_task()

static int session_end_if_deferred_task ( void *  data)
static

Definition at line 683 of file res_pjsip_refer.c.

684{
685 struct ast_sip_session *session = data;
686
688 ao2_ref(session, -1);
689 return 0;
690}

References ao2_ref, ast_sip_session_end_if_deferred(), and session.

Referenced by refer_attended_task().

◆ sip_refer_send()

static int sip_refer_send ( const struct ast_refer refer)
static

Definition at line 1492 of file res_pjsip_refer.c.

1493{
1494 struct refer_data *rdata;
1495 int res;
1496
1498 ast_log(LOG_ERROR, "SIP REFER - a 'To' URI must be specified\n");
1499 return -1;
1500 }
1501
1502 rdata = refer_data_create(refer);
1503 if (!rdata) {
1504 return -1;
1505 }
1506
1508 ao2_ref(rdata, -1);
1509
1510 return res;
1511}
static struct refer_data * refer_data_create(const struct ast_refer *refer)
static int refer_send(void *data)

References ao2_ref, ast_log, ast_refer_get_to(), ast_sip_push_task_wait_serializer, ast_strlen_zero(), LOG_ERROR, refer_data::refer, refer_data_create(), refer_send(), and refer_serializer.

◆ transfer_ari_state_destroy()

static void transfer_ari_state_destroy ( void *  obj)
static

Destructor of the state used for the ARI transfer.

Definition at line 111 of file res_pjsip_refer.c.

112{
113 struct transfer_ari_state *state = obj;
114 char *chan_name = ast_strdupa(state->transferer_chan ? ast_channel_name(state->transferer_chan) : "unknown");
115 SCOPE_ENTER(3, "%s: state destructor", chan_name);
116
117 ao2_cleanup(state->transferer);
118 ao2_cleanup(state->other_session);
119 ast_channel_cleanup(state->transferer_chan);
120 ast_free(state->referred_by);
121 ast_free(state->protocol_id);
122 ao2_cleanup(state->params);
123
124 SCOPE_EXIT_RTN("%s: done", chan_name);
125}

References ao2_cleanup, ast_channel_cleanup, ast_channel_name(), ast_free, ast_strdupa, SCOPE_ENTER, and SCOPE_EXIT_RTN.

Referenced by refer_incoming_ari_request().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2198 of file res_pjsip_refer.c.

2199{
2204
2205 return 0;
2206}
void ast_sip_unregister_service(pjsip_module *module)
Definition res_pjsip.c:127
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.

References ast_sip_session_unregister_supplement(), ast_sip_unregister_service(), ast_taskprocessor_unreference(), refer_out_of_dialog_module, refer_progress_module, refer_serializer, and refer_supplement.

◆ vars_to_headers()

static enum pjsip_status_code vars_to_headers ( const struct ast_refer refer,
pjsip_tx_data *  tdata 
)
static

Definition at line 1143 of file res_pjsip_refer.c.

1144{
1145 const char *name;
1146 const char *value;
1148
1149 for (iter = ast_refer_var_iterator_init(refer);
1152 if (!is_refer_var_blocked(name)) {
1153 ast_sip_add_header(tdata, name, value);
1154 }
1155 }
1157
1158 return PJSIP_SC_OK;
1159}
void ast_refer_var_unref_current(struct ast_refer_var_iterator *iter)
Unref a refer var from inside an iterator loop.
Definition refer.c:372
int ast_refer_var_iterator_next(struct ast_refer_var_iterator *iter, const char **name, const char **value)
Get the next variable name and value.
Definition refer.c:351
struct ast_refer_var_iterator * ast_refer_var_iterator_init(const struct ast_refer *refer)
Create a new refer variable iterator.
Definition refer.c:337
void ast_refer_var_iterator_destroy(struct ast_refer_var_iterator *iter)
Destroy a refer variable iterator.
Definition refer.c:378
static int is_refer_var_blocked(const char *name)
struct ao2_iterator iter
Definition refer.c:333
int value
Definition syslog.c:37

References ast_refer_var_iterator_destroy(), ast_refer_var_iterator_init(), ast_refer_var_iterator_next(), ast_refer_var_unref_current(), ast_sip_add_header(), is_refer_var_blocked(), ast_refer_var_iterator::iter, name, and value.

Referenced by refer_send().

◆ xfer_response_code2sip()

static int xfer_response_code2sip ( enum ast_transfer_result  xfer_code)
static

Definition at line 711 of file res_pjsip_refer.c.

712{
713 int response;
714
715 response = 503;
716 switch (xfer_code) {
718 response = 400;
719 break;
721 response = 403;
722 break;
724 response = 500;
725 break;
727 response = 200;
728 break;
729 }
730 return response;
731}
@ AST_BRIDGE_TRANSFER_NOT_PERMITTED
Definition bridge.h:1163
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition bridge.h:1161
@ AST_BRIDGE_TRANSFER_INVALID
Definition bridge.h:1165
@ AST_BRIDGE_TRANSFER_FAIL
Definition bridge.h:1167

References AST_BRIDGE_TRANSFER_FAIL, AST_BRIDGE_TRANSFER_INVALID, AST_BRIDGE_TRANSFER_NOT_PERMITTED, and AST_BRIDGE_TRANSFER_SUCCESS.

Referenced by refer_attended_task(), refer_incoming_attended_request(), and refer_incoming_blind_request().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Blind and Attended Transfer Support" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip,res_pjsip_session,res_pjsip_pubsub", }
static

Definition at line 2214 of file res_pjsip_refer.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2214 of file res_pjsip_refer.c.

◆ refer_out_of_dialog_module

pjsip_module refer_out_of_dialog_module
static

REFER Out-of-dialog module, used to attach session data structure to subscription.

Definition at line 1167 of file res_pjsip_refer.c.

1167 {
1168 .name = { "REFER Out-of-dialog Module", 26 },
1169 .id = -1,
1170 .on_tx_request = refer_on_tx_request,
1171 /* Ensure that we are called after res_pjsp_nat module and before transport priority */
1172 .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 4,
1173};
static pj_status_t refer_on_tx_request(pjsip_tx_data *tdata)

Referenced by load_module(), refer_client_on_evsub_state(), refer_on_tx_request(), refer_send(), refer_unreference_dialog(), and unload_module().

◆ refer_progress_evsub_cb

pjsip_evsub_user refer_progress_evsub_cb
static
Initial value:
= {
.on_evsub_state = refer_progress_on_evsub_state,
}
static void refer_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
Callback for REFER subscription state changes.

Callback structure for subscription.

Definition at line 507 of file res_pjsip_refer.c.

507 {
508 .on_evsub_state = refer_progress_on_evsub_state,
509};

Referenced by refer_progress_alloc().

◆ refer_progress_module

pjsip_module refer_progress_module
static
Initial value:
= {
.name = { "REFER Progress", 14 },
.id = -1,
}

REFER Progress module, used to attach REFER progress structure to subscriptions.

Definition at line 105 of file res_pjsip_refer.c.

105 {
106 .name = { "REFER Progress", 14 },
107 .id = -1,
108};

Referenced by dlg_releaser_task(), load_module(), refer_progress_alloc(), refer_progress_destroy(), refer_progress_on_evsub_state(), and unload_module().

◆ refer_serializer

struct ast_taskprocessor* refer_serializer
static

◆ refer_supplement

struct ast_sip_session_supplement refer_supplement
static
Initial value:
= {
.incoming_request = refer_incoming_request,
.outgoing_request = refer_outgoing_request,
}
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition res_pjsip.h:3396
static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static int refer_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)

Definition at line 2162 of file res_pjsip_refer.c.

2162 {
2164 .incoming_request = refer_incoming_request,
2165 .outgoing_request = refer_outgoing_request,
2166};

Referenced by load_module(), and unload_module().

◆ refer_tech

const struct ast_refer_tech refer_tech
static
Initial value:
= {
.name = "pjsip",
.refer_send = sip_refer_send,
}
static int sip_refer_send(const struct ast_refer *refer)

Definition at line 1513 of file res_pjsip_refer.c.

1513 {
1514 .name = "pjsip",
1515 .refer_send = sip_refer_send,
1516};

Referenced by ast_refer_send(), and load_module().