Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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. More...
 
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. More...
 
static int invite_replaces (void *data)
 Task for invite replaces. More...
 
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. More...
 
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. More...
 
static void refer_attended_destroy (void *obj)
 Destructor for attended transfer task. More...
 
static int refer_attended_task (void *data)
 Task for attended transfer executed by attended->transferer_second serializer. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
static void refer_progress_framehook_destroy (void *data)
 Destroy callback for monitoring framehook. More...
 
static struct refer_progress_notificationrefer_progress_notification_alloc (struct refer_progress *progress, int response, pjsip_evsub_state state)
 Allocator for REFER Progress notification structure. More...
 
static void refer_progress_notification_destroy (void *obj)
 Destructor for REFER Progress notification structure. More...
 
static int refer_progress_notify (void *data)
 Serialized callback for subscription notification. More...
 
static void refer_progress_on_evsub_state (pjsip_evsub *sub, pjsip_event *event)
 Callback for REFER subscription state changes. More...
 
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. More...
 
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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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. More...
 
static pjsip_evsub_user refer_progress_evsub_cb
 Callback structure for subscription. More...
 
static pjsip_module refer_progress_module
 REFER Progress module, used to attach REFER progress structure to subscriptions. More...
 
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 952 of file res_pjsip_refer.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2149 of file res_pjsip_refer.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2149 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 2064 of file res_pjsip_refer.c.

2065{
2066 const char *var_value;
2067 pj_str_t pj_header_name;
2068 pjsip_hdr *header;
2069
2070 var_value = pbx_builtin_getvar_helper(chan, var_name);
2071 if (ast_strlen_zero(var_value)) {
2072 return;
2073 }
2074
2075 pj_cstr(&pj_header_name, header_name);
2076 header = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_header_name, NULL);
2077 if (header) {
2078 return;
2079 }
2080 ast_sip_add_header(tdata, header_name, var_value);
2081}
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
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:2008
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65

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 1468 of file res_pjsip_refer.c.

1469{
1470 struct ast_refer_param param;
1471
1472 param.param_name = ast_strdup(key);
1473 if (!param.param_name) {
1474 return 0;
1475 }
1476
1477 param.param_value = copy_string(str);
1478 if (!param.param_value) {
1479 ast_free((char *) param.param_name);
1480 return 0;
1481 }
1482
1483 if (AST_VECTOR_APPEND(params, param) != 0) {
1484 ast_free((char *) param.param_name);
1485 ast_free((char *) param.param_value);
1486 return 0;
1487 }
1488 return 1;
1489}
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:256

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 140 of file res_pjsip_refer.c.

141{
142 return ast_refer_notify_transfer_request(state->transferer_chan, state->referred_by,
143 state->exten, state->protocol_id,
144 state->other_session ? state->other_session->channel : NULL,
145 state->params, state->last_response);
146}
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

References ast_refer_notify_transfer_request(), and NULL.

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 2149 of file res_pjsip_refer.c.

◆ copy_string()

static char * copy_string ( struct pj_str_t *  str)
static

Definition at line 1457 of file res_pjsip_refer.c.

1458{
1459 int len = pj_strlen(str) + 1;
1460 char *dst = ast_malloc(len);
1461 if (!dst) {
1462 return NULL;
1463 }
1464 ast_copy_pj_str(dst, str, len);
1465 return dst;
1466}
#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:2201

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 631 of file res_pjsip_refer.c.

632{
633 struct ast_sip_session *session = data;
634
637 ao2_ref(session, -1);
638 return 0;
639}
static struct ast_mansession session
#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(), and refer_progress_notify().

◆ dlg_releaser_task()

static int dlg_releaser_task ( void *  data)
static

Definition at line 462 of file res_pjsip_refer.c.

462 {
463 pjsip_dlg_dec_session((pjsip_dialog *)data, &refer_progress_module);
464 return 0;
465}
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 1115 of file res_pjsip_refer.c.

1116{
1117 const pj_str_t REFER_TO = { "Refer-To", 8 };
1118 pjsip_generic_string_hdr *refer_to;
1119 pjsip_uri *parsed_uri;
1120
1121 if (!(refer_to = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL))
1122 || !(parsed_uri = pjsip_parse_uri(tdata->pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0))
1123 || (!PJSIP_URI_SCHEME_IS_SIP(parsed_uri) && !PJSIP_URI_SCHEME_IS_SIPS(parsed_uri))) {
1124 return NULL;
1125 }
1126
1127 return parsed_uri;
1128}

References NULL.

Referenced by refer_on_tx_request().

◆ invite_replaces()

static int invite_replaces ( void *  data)
static

Task for invite replaces.

Definition at line 1785 of file res_pjsip_refer.c.

1786{
1787 struct invite_replaces *invite = data;
1788
1789 if (!invite->session->channel) {
1790 return -1;
1791 }
1792
1794 invite->channel = invite->session->channel;
1795
1797 return 0;
1798}
struct ast_bridge * ast_bridge_transfer_acquire_bridge(struct ast_channel *chan)
Acquire the channel's bridge for transfer purposes.
Definition: bridge.c:4477
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2997
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 1047 of file res_pjsip_refer.c.

1048{
1049 int i;
1050
1051 /* Don't block the Max-Forwards header because the user can override it */
1052 static const char *hdr[] = {
1053 "To",
1054 "From",
1055 "Via",
1056 "Route",
1057 "Contact",
1058 "Call-ID",
1059 "CSeq",
1060 "Allow",
1061 "Content-Length",
1062 "Content-Type",
1063 "Request-URI",
1064 };
1065
1066 for (i = 0; i < ARRAY_LEN(hdr); ++i) {
1067 if (!strcasecmp(name, hdr[i])) {
1068 /* Block addition of this header. */
1069 return 1;
1070 }
1071 }
1072 return 0;
1073}
static const char name[]
Definition: format_mp3.c:68
#define ARRAY_LEN(a)
Definition: utils.h:666

References ARRAY_LEN, and name.

Referenced by vars_to_headers().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2103 of file res_pjsip_refer.c.

2104{
2105 const pj_str_t str_norefersub = { "norefersub", 10 };
2106
2107 pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint());
2108 pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint());
2109
2110 if (ast_sip_get_norefersub()) {
2111 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub);
2112 }
2113
2116 }
2117
2119 if (!refer_serializer) {
2122 }
2123
2127
2129
2131}
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2094
#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:117
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
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 364 of file res_pjsip_refer.c.

365{
366 struct refer_progress *progress = data;
367 struct refer_progress_notification *notification = NULL;
368
369 /* We only care about frames *to* the channel */
370 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
371 return f;
372 }
373
374 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
377 && f->datalen >= sizeof(enum ast_control_transfer)) {
379 switch (*message) {
381 notification = refer_progress_notification_alloc(progress, 603, PJSIP_EVSUB_STATE_TERMINATED);
382 break;
384 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
385 break;
387 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
388 break;
390 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
391 break;
393 break;
394 }
395 progress->ari_state->last_response = *message;
396 }
397
398 /* If a notification is due to be sent push it to the thread pool */
399 if (notification) {
400 /* If the subscription is being terminated we don't need the frame hook any longer */
401 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
402 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
403 ast_channel_name(chan));
404 ast_framehook_detach(chan, progress->framehook);
405 }
406
407 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
408 ao2_cleanup(notification);
409 }
410 }
411
412 return f;
413}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
const char * ast_channel_name(const struct ast_channel *chan)
@ 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
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
ast_control_transfer
@ AST_TRANSFER_FAILED
@ AST_TRANSFER_UNAVAILABLE
@ AST_TRANSFER_SUCCESS
@ AST_TRANSFER_PROGRESS
@ AST_TRANSFER_INVALID
@ AST_FRAME_CONTROL
@ AST_CONTROL_TRANSFER
#define ast_debug(level,...)
Log a DEBUG message.
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.
union ast_frame::@228 data
struct ast_frame_subclass subclass
enum ast_frame_type frametype
Definition: astman.c:222
Definition: dsp.c:117
REFER Progress notification structure.
pjsip_evsub_state state
Subscription state.
REFER Progress structure.

References ao2_cleanup, ast_channel_name(), AST_CONTROL_TRANSFER, ast_debug, AST_FRAME_CONTROL, ast_framehook_detach(), AST_FRAMEHOOK_EVENT_WRITE, ast_sip_push_task(), 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, NULL, ast_frame::ptr, refer_progress_notification_alloc(), refer_progress_notify(), 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 595 of file res_pjsip_refer.c.

598{
599 struct refer_attended *attended;
600
601 attended = ao2_alloc_options(sizeof(*attended), refer_attended_destroy,
603 if (!attended) {
604 return NULL;
605 }
606
607 ao2_ref(transferer, +1);
608 attended->transferer = transferer;
613
614 if (progress) {
615 ao2_ref(progress, +1);
616 attended->progress = progress;
617 }
618
619 return attended;
620}
@ 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 584 of file res_pjsip_refer.c.

585{
586 struct refer_attended *attended = obj;
587
588 ao2_cleanup(attended->transferer);
591 ao2_cleanup(attended->progress);
592}
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3019

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 673 of file res_pjsip_refer.c.

674{
675 struct refer_attended *attended = data;
676 int response;
677 int (*task_cb)(void *data);
678
679 if (attended->transferer_second->channel) {
680 ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
683
685 attended->transferer_chan,
686 attended->transferer_second->channel));
687
688 ast_debug(3, "Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
691 response);
692 } else {
693 ast_debug(3, "Received REFER request on channel '%s' but other channel has gone.\n",
695 response = 603;
696 }
697
698 if (attended->progress) {
699 struct refer_progress_notification *notification;
700
701 notification = refer_progress_notification_alloc(attended->progress, response,
702 PJSIP_EVSUB_STATE_TERMINATED);
703 if (notification) {
704 if (ast_sip_push_task(attended->progress->serializer, refer_progress_notify, notification)) {
705 ao2_cleanup(notification);
706 }
707 }
708 }
709
710 if (response == 200) {
712 } else {
714 }
716 task_cb, attended->transferer)) {
717 /* Gave the ref to the pushed task. */
718 attended->transferer = NULL;
719 } else {
720 /* Do this anyway even though it is the wrong serializer. */
722 }
723
724 ao2_ref(attended, -1);
725 return 0;
726}
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
Definition: bridge.c:4746
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 745 of file res_pjsip_refer.c.

747{
748 struct refer_blind *refer = user_data_wrapper->data;
749 pjsip_generic_string_hdr *referred_by;
750
751 static const pj_str_t str_referred_by = { "Referred-By", 11 };
752 static const pj_str_t str_referred_by_s = { "b", 1 };
753 const char *get_xfrdata;
754
755 pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
756
757 if (refer->progress && !refer->attended && !refer->progress->refer_blind_progress) {
758 /* If blind transfer and endpoint doesn't want to receive all the progress details */
760 PJSIP_EVSUB_STATE_TERMINATED);
761
762 if (notification) {
763 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
764 ao2_cleanup(notification);
765 }
766 }
767 } else if (refer->progress) {
768 /* If attended transfer and progress monitoring is being done attach a frame hook so we can monitor it */
769 struct ast_framehook_interface hook = {
771 .event_cb = refer_progress_framehook,
773 .data = refer->progress,
774 .disable_inheritance = 1,
775 };
776
778 if (!refer->progress->transferee) {
780 PJSIP_EVSUB_STATE_TERMINATED);
781
782 ast_log(LOG_WARNING, "Could not copy channel name '%s' during transfer - assuming success\n",
783 ast_channel_name(chan));
784
785 if (notification) {
786 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
787 ao2_cleanup(notification);
788 }
789 }
790 }
791
792 /* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
793 ao2_ref(user_data_wrapper, +1);
794 refer->progress->transfer_data = user_data_wrapper;
795
796 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
797 ao2_ref(refer->progress, +1);
798
799 /* If we can't attach a frame hook for whatever reason send a notification of success immediately */
800 ast_channel_lock(chan);
801 refer->progress->framehook = ast_framehook_attach(chan, &hook);
802 ast_channel_unlock(chan);
803 if (refer->progress->framehook < 0) {
805 PJSIP_EVSUB_STATE_TERMINATED);
806
807 ast_log(LOG_WARNING, "Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
808 ast_channel_name(chan));
809
810 if (notification) {
811 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
812 ao2_cleanup(notification);
813 }
814 }
815
816 ao2_cleanup(refer->progress);
817 }
818
819 /* We need to bump the reference count for the stasis subscription */
820 ao2_ref(refer->progress, +1);
821 /* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
822 * detect if the transfer target has answered the call
823 */
825 if (!refer->progress->bridge_sub) {
827 PJSIP_EVSUB_STATE_TERMINATED);
828
829 ast_log(LOG_WARNING, "Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success\n",
830 ast_channel_name(chan));
831
832 if (notification) {
833 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
834 ao2_cleanup(notification);
835 }
836 }
837
838 ast_channel_lock(chan);
840 ast_channel_unlock(chan);
841
842 ao2_cleanup(refer->progress);
843 } else {
847 }
848 }
849
850 pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL));
851
852 ast_channel_lock(chan);
853 if ((get_xfrdata = pbx_builtin_getvar_helper(chan, "GET_TRANSFERRER_DATA"))) {
854 get_xfrdata = ast_strdupa(get_xfrdata);
855 }
856 ast_channel_unlock(chan);
857 if (!ast_strlen_zero(get_xfrdata)) {
858 const pjsip_msg * msg = refer->rdata->msg_info.msg;
859 const struct pjsip_hdr *end = &msg->hdr;
860 struct pjsip_hdr *hdr = end->next;
861 struct ast_str *pbxvar = ast_str_create(64); /* initial buffer for variable name, extended on demand */
862 char buf[4096]; /* should be enough for one header value */
863 const char *prefix = get_xfrdata;
864
865 /* The '*' alone matches all headers. */
866 if (!strcmp(prefix, "*")) {
867 prefix = "";
868 }
869 if (pbxvar) {
870 for (; hdr != end; hdr = hdr->next) {
871 if (!pj_strnicmp2(&hdr->name, prefix, strlen(prefix))) {
872 const int hdr_name_strlen = pj_strlen(&hdr->name);
873 const int hdr_name_bytes = hdr_name_strlen + 1; /* +1 for string NULL terminator */
874 char hdr_name[hdr_name_bytes];
875 int len;
876 char *value_str;
877
878 ast_copy_pj_str(hdr_name, &hdr->name, hdr_name_bytes);
879 len = pjsip_hdr_print_on(hdr, buf, sizeof(buf) - 1);
880 if (len < 0) {
881 /* ignore too long headers */
882 ast_log(LOG_WARNING, "Could not store header '%s' from transfer on channel '%s' - too long text\n", hdr_name, ast_channel_name(chan));
883 continue;
884 }
885 buf[len] = '\0';
886
887 /* Get value - remove header name (before ':') from buf and trim blanks. */
888 value_str = strchr(buf, ':');
889 if (!value_str) {
890 /* Ignore header without value */
891 continue;
892 }
893 value_str = ast_strip(value_str + 1); /* +1 to get string right after the ':' delimiter (i.e. header value) */
894
895 ast_str_set(&pbxvar, -1, "~HASH~TRANSFER_DATA~%.*s~", hdr_name_strlen, hdr_name);
896 pbx_builtin_setvar_helper(chan, ast_str_buffer(pbxvar), value_str);
897 ast_debug(5, "On channel '%s' set TRANSFER_DATA variable '%s' to value '%s' \n", ast_channel_name(chan), hdr_name, value_str);
898 }
899 }
900 ast_free(pbxvar);
901 } else {
902 ast_log(LOG_ERROR, "Channel '%s' failed to allocate buffer for TRANSFER_DATA variable\n", ast_channel_name(chan));
903 }
904 }
905
906 referred_by = pjsip_msg_find_hdr_by_names(refer->rdata->msg_info.msg,
907 &str_referred_by, &str_referred_by_s, NULL);
908 if (referred_by) {
909 size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
910 char *uri = ast_alloca(uri_size);
911
912 ast_copy_pj_str(uri, &referred_by->hvalue, uri_size);
913 pbx_builtin_setvar_helper(chan, "__SIPREFERREDBYHDR", S_OR(uri, NULL));
914 } else {
915 pbx_builtin_setvar_helper(chan, "SIPREFERREDBYHDR", NULL);
916 }
917
918 if (refer->replaces) {
919 char replaces[512];
920 char *replaces_val = NULL;
921 int len;
922
923 len = pjsip_hdr_print_on(refer->replaces, replaces, sizeof(replaces) - 1);
924 if (len != -1) {
925 /* pjsip_hdr_print_on does not NULL terminate the buffer */
926 replaces[len] = '\0';
927 replaces_val = replaces + sizeof("Replaces:");
928 }
929 pbx_builtin_setvar_helper(chan, "__SIPREPLACESHDR", replaces_val);
930 } else {
931 pbx_builtin_setvar_helper(chan, "SIPREPLACESHDR", NULL);
932 }
933
934 if (refer->refer_to) {
935 char refer_to[PJSIP_MAX_URL_SIZE];
936
937 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->refer_to, refer_to, sizeof(refer_to));
938 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", S_OR(refer_to, NULL));
939 } else {
940 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", NULL);
941 }
942}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ast_channel_lock(chan)
Definition: channel.h:2972
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2973
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:144
#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:1050
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:1104
#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.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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 * 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, 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 1201 of file res_pjsip_refer.c.

1202{
1203 pjsip_tx_data *tdata;
1204 RAII_VAR(struct ast_sip_endpoint *, endpt, NULL, ao2_cleanup);
1206 int refer_success;
1207 int res = 0;
1208
1209 if (!event) {
1210 return;
1211 }
1212
1213 refer_data = pjsip_evsub_get_mod_data(sub, refer_out_of_dialog_module.id);
1214 if (!refer_data || !refer_data->dlg) {
1215 return;
1216 }
1217
1219
1220 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
1221 /* Check if subscription is suppressed and terminate and send completion code, if so. */
1222 pjsip_rx_data *rdata;
1223 pjsip_generic_string_hdr *refer_sub;
1224 const pj_str_t REFER_SUB = { "Refer-Sub", 9 };
1225
1226 ast_debug(3, "Refer accepted by %s\n", endpt ? ast_sorcery_object_get_id(endpt) : "(unknown endpoint)");
1227
1228 /* Check if response message */
1229 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1230 rdata = event->body.tsx_state.src.rdata;
1231
1232 /* Find Refer-Sub header */
1233 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &REFER_SUB, NULL);
1234
1235 /* Check if subscription is suppressed. If it is, the far end will not terminate it,
1236 * and the subscription will remain active until it times out. Terminating it here
1237 * eliminates the unnecessary timeout.
1238 */
1239 if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
1240 /* Since no subscription is desired, assume that call has been referred successfully
1241 * and terminate subscription.
1242 */
1243 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1244 pjsip_evsub_terminate(sub, PJ_TRUE);
1245 res = -1;
1246 }
1247 }
1248 } else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
1249 pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
1250 /* Check for NOTIFY complete or error. */
1251 pjsip_msg *msg;
1252 pjsip_msg_body *body;
1253 pjsip_status_line status_line = { .code = 0 };
1254 pj_bool_t is_last;
1255 pj_status_t status;
1256
1257 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1258 pjsip_rx_data *rdata;
1259 pj_str_t refer_str;
1260 pj_cstr(&refer_str, "REFER");
1261
1262 rdata = event->body.tsx_state.src.rdata;
1263 msg = rdata->msg_info.msg;
1264
1265 if (msg->type == PJSIP_RESPONSE_MSG
1266 && (event->body.tsx_state.tsx->status_code == 401
1267 || event->body.tsx_state.tsx->status_code == 407)
1268 && pj_stristr(&refer_str, &event->body.tsx_state.tsx->method.name)
1269 && ++refer_data->authentication_challenge_count < MAX_RX_CHALLENGES
1270 && endpt) {
1271
1272 if (!ast_sip_create_request_with_auth(&endpt->outbound_auths,
1273 event->body.tsx_state.src.rdata, event->body.tsx_state.tsx->last_tx, &tdata)) {
1274 /* Send authed REFER */
1276 goto out;
1277 }
1278 }
1279
1280 if (msg->type == PJSIP_REQUEST_MSG) {
1281 if (!pjsip_method_cmp(&msg->line.req.method, pjsip_get_notify_method())) {
1282 body = msg->body;
1283 if (body && !pj_stricmp2(&body->content_type.type, "message")
1284 && !pj_stricmp2(&body->content_type.subtype, "sipfrag")) {
1285 pjsip_parse_status_line((char *)body->data, body->len, &status_line);
1286 }
1287 }
1288 } else {
1289 status_line.code = msg->line.status.code;
1290 status_line.reason = msg->line.status.reason;
1291 }
1292 } else {
1293 status_line.code = 500;
1294 status_line.reason = *pjsip_get_status_text(500);
1295 }
1296
1297 is_last = (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED);
1298 /* If the status code is >= 200, the subscription is finished. */
1299 if (status_line.code >= 200 || is_last) {
1300 res = -1;
1301
1302 refer_success = status_line.code >= 200 && status_line.code < 300;
1303
1304 /* If subscription not terminated and subscription is finished (status code >= 200)
1305 * terminate it */
1306 if (!is_last) {
1307 pjsip_tx_data *tdata;
1308
1309 status = pjsip_evsub_initiate(sub, pjsip_get_subscribe_method(), 0, &tdata);
1310 if (status == PJ_SUCCESS) {
1311 pjsip_evsub_send_request(sub, tdata);
1312 }
1313 }
1314 ast_debug(3, "Refer completed: %d %.*s (%s)\n",
1315 status_line.code,
1316 (int)status_line.reason.slen, status_line.reason.ptr,
1317 refer_success ? "Success" : "Failure");
1318 }
1319 }
1320
1321out:
1322 if (res) {
1324 }
1325}
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.
struct stasis_forward * sub
Definition: res_corosync.c:240
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:214
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:1979
#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:2317
An entity with which Asterisk communicates.
Definition: res_pjsip.h:1051
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:941

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 983 of file res_pjsip_refer.c.

984{
985 char *uri_params;
986 const char *destination;
988
989 if (!rdata) {
990 return NULL;
991 }
992
993 /* typecast to suppress const warning */
994 rdata->refer = ast_refer_ref((struct ast_refer *) refer);
996
997 /* To starts with 'pjsip:' which needs to be removed. */
998 if (!(destination = strchr(destination, ':'))) {
999 goto failure;
1000 }
1001 ++destination;/* Now skip the ':' */
1002
1004 if (!rdata->destination) {
1005 goto failure;
1006 }
1007
1009 if (!rdata->from) {
1010 goto failure;
1011 }
1012
1014 if (!rdata->refer_to) {
1015 goto failure;
1016 }
1018
1019 /*
1020 * Sometimes from URI can contain URI parameters, so remove them.
1021 *
1022 * sip:user;user-options@domain;uri-parameters
1023 */
1024 uri_params = strchr(rdata->from, '@');
1025 if (uri_params && (uri_params = strchr(uri_params, ';'))) {
1026 *uri_params = '\0';
1027 }
1028 return rdata;
1029
1030failure:
1031 ao2_cleanup(rdata);
1032 return NULL;
1033}
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
char * destination
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 972 of file res_pjsip_refer.c.

973{
974 struct refer_data *rdata = obj;
975
976 ast_free(rdata->destination);
977 ast_free(rdata->from);
978 ast_free(rdata->refer_to);
979
980 ast_refer_destroy(rdata->refer);
981}
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 1492 of file res_pjsip_refer.c.

1494{
1495 int parsed_len;
1496 pjsip_replaces_hdr *replaces;
1497 pjsip_generic_string_hdr *referred_hdr;
1498
1499
1501
1502 struct ast_framehook_interface hook = {
1504 .event_cb = refer_ari_progress_framehook,
1506 .data = progress,
1507 .disable_inheritance = 1,
1508 };
1509
1510 static const pj_str_t str_referred_by = { "Referred-By", 11 };
1511 static const pj_str_t str_referred_by_s = { "b", 1 };
1512 static const pj_str_t str_replaces = { "Replaces", 8 };
1513
1514
1516 if (!state) {
1517 return 500;
1518 }
1519
1520 state->last_response = AST_TRANSFER_INVALID;
1521
1522 state->params = ao2_alloc(sizeof(struct ast_refer_params), refer_params_destroy);
1523 if (!state->params) {
1524 return 500;
1525 }
1526 AST_VECTOR_INIT(state->params, 0);
1527
1528
1529 ast_channel_ref(session->channel);
1530 state->transferer_chan = session->channel;
1531
1532 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1533 ast_copy_pj_str(state->exten, &target->user, sizeof(state->exten));
1534
1535 /*
1536 * We may want to match in the dialplan without any user
1537 * options getting in the way.
1538 */
1540
1541 referred_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg,
1542 &str_referred_by, &str_referred_by_s, NULL);
1543 if (referred_hdr) {
1544 state->referred_by = copy_string(&referred_hdr->hvalue);
1545 if (!state->referred_by) {
1546 return 500;
1547 }
1548 }
1549
1550 if (replaces_param) {
1551 pjsip_dialog *dlg;
1552 pj_str_t replaces_content = { 0, };
1553 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1554
1555 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1556 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1557 pj_strlen(&replaces_content), &parsed_len))) {
1558 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1560 return 400;
1561 }
1562
1563 dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE);
1564 if (dlg) {
1565 state->other_session = ast_sip_dialog_get_session(dlg);
1566 pjsip_dlg_dec_lock(dlg);
1567 }
1568
1569 state->protocol_id = copy_string(&replaces->call_id);
1570 if (!state->protocol_id) {
1571 return 500;
1572 }
1573
1574 if (!add_refer_param(state->params, "from", &replaces->from_tag)) {
1575 return 500;
1576 }
1577
1578 if (!add_refer_param(state->params, "to", &replaces->to_tag)) {
1579 return 500;
1580 }
1581 }
1582
1583 ao2_ref(session, +1);
1585 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted ari-only transfer but could not defer termination, rejecting\n",
1586 ast_channel_name(session->channel),
1589 return 500;
1590 }
1591 state->transferer = session;
1592
1593
1594 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
1595 ao2_ref(progress, +1);
1596 ast_channel_lock(session->channel);
1597 progress->framehook = ast_framehook_attach(session->channel, &hook);
1598 ast_channel_unlock(session->channel);
1599
1600 if (progress->framehook < 0) {
1602 return 500;
1603 }
1604
1605 if (ari_notify(state)) {
1606 ast_channel_lock(session->channel);
1607 ast_framehook_detach(session->channel, progress->framehook);
1608 progress->framehook = -1;
1610 ast_channel_unlock(session->channel);
1611 return 500;
1612 }
1613
1614 /* Transfer ownership to the progress */
1615 progress->ari_state = state;
1616 state = NULL;
1617 return 200;
1618}
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
enum cc_state state
Definition: ccss.c:399
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3504
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.
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.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

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_session_defer_termination(), AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_sorcery_object_get_id(), AST_TRANSFER_INVALID, AST_VECTOR_INIT, copy_string(), LOG_ERROR, NULL, RAII_VAR, refer_ari_progress_framehook(), refer_params_destroy(), refer_progress_framehook_destroy(), session, state, 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 1620 of file res_pjsip_refer.c.

1622{
1623 const pj_str_t str_replaces = { "Replaces", 8 };
1624 pj_str_t replaces_content;
1625 pjsip_replaces_hdr *replaces;
1626 int parsed_len;
1627 pjsip_dialog *dlg;
1628
1629 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1630
1631 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1632 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1633 pj_strlen(&replaces_content), &parsed_len))) {
1634 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1636 return 400;
1637 }
1638
1639 /* See if the dialog is local, or remote */
1640 if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
1641 RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
1642 struct refer_attended *attended;
1643
1644 pjsip_dlg_dec_lock(dlg);
1645
1646 if (!other_session) {
1647 ast_debug(3, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it\n",
1649 return 603;
1650 }
1651
1652 /* We defer actually doing the attended transfer to the other session so no deadlock can occur */
1653 if (!(attended = refer_attended_alloc(session, other_session, progress))) {
1654 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",
1656 return 500;
1657 }
1658
1660 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not defer termination, rejecting\n",
1662 ao2_cleanup(attended);
1663 return 500;
1664 }
1665
1666 /* Push it to the other session, which will have both channels with minimal locking */
1667 if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {
1670 ao2_cleanup(attended);
1671 return 500;
1672 }
1673
1674 ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
1675 ast_channel_name(session->channel));
1676
1677 return 200;
1678 } else {
1679 const char *context;
1680 struct refer_blind refer = { 0, };
1681 int response;
1682
1684
1685 if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
1686 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",
1688 return 404;
1689 }
1690
1691 refer.context = context;
1692 refer.progress = progress;
1693 refer.rdata = rdata;
1694 refer.replaces = replaces;
1695 refer.refer_to = target_uri;
1696 refer.attended = 1;
1697
1699 ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting\n",
1700 ast_channel_name(session->channel),
1702 return 500;
1703 }
1704
1706 "external_replaces", context, refer_blind_callback, &refer));
1707
1709 if (response != 200) {
1711 }
1712
1713 return response;
1714 }
1715}
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:4494
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:4190
#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.

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, voicemailpwcheck::context, 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, 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 1717 of file res_pjsip_refer.c.

1719{
1720 const char *context;
1721 char exten[AST_MAX_EXTENSION];
1722 struct refer_blind refer = { 0, };
1723 int response;
1724
1725 /* If no explicit transfer context has been provided use their configured context */
1727
1728 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1729 ast_copy_pj_str(exten, &target->user, sizeof(exten));
1730
1731 /*
1732 * We may want to match in the dialplan without any user
1733 * options getting in the way.
1734 */
1736
1737 /* Uri without exten */
1738 if (ast_strlen_zero(exten)) {
1739 ast_copy_string(exten, "s", sizeof(exten));
1740 ast_debug(3, "Channel '%s' from endpoint '%s' attempted blind transfer to a target without extension. Target was set to 's@%s'\n",
1742 }
1743
1744 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
1745 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
1746 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context);
1747 return 404;
1748 }
1749
1750 refer.context = context;
1751 refer.progress = progress;
1752 refer.rdata = rdata;
1753 refer.refer_to = target;
1754 refer.attended = 0;
1755
1757 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer but could not defer termination, rejecting\n",
1758 ast_channel_name(session->channel),
1760 return 500;
1761 }
1762
1764 exten, context, refer_blind_callback, &refer));
1765
1767 if (response != 200) {
1769 }
1770
1771 return response;
1772}
#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, voicemailpwcheck::context, 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 1800 of file res_pjsip_refer.c.

1801{
1802 pjsip_dialog *other_dlg = NULL;
1803 pjsip_tx_data *packet;
1804 int response = 0;
1805 RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup);
1806 struct invite_replaces invite;
1807
1808 /* If a Replaces header is present make sure it is valid */
1809 if (pjsip_replaces_verify_request(rdata, &other_dlg, PJ_TRUE, &packet) != PJ_SUCCESS) {
1810 response = packet->msg->line.status.code;
1811 ast_assert(response != 0);
1812 pjsip_tx_data_dec_ref(packet);
1813 goto inv_replace_failed;
1814 }
1815
1816 /* If no other dialog exists then this INVITE request does not have a Replaces header */
1817 if (!other_dlg) {
1818 return 0;
1819 }
1820
1821 other_session = ast_sip_dialog_get_session(other_dlg);
1822 pjsip_dlg_dec_lock(other_dlg);
1823
1824 /* Don't accept an in-dialog INVITE with Replaces as it does not make much sense */
1825 if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
1826 response = 488;
1827 goto inv_replace_failed;
1828 }
1829
1830 if (!other_session) {
1831 ast_debug(3, "INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist\n",
1833 response = 481;
1834 goto inv_replace_failed;
1835 }
1836
1837 invite.session = other_session;
1838
1839 if (ast_sip_push_task_wait_serializer(other_session->serializer, invite_replaces,
1840 &invite)) {
1841 response = 481;
1842 goto inv_replace_failed;
1843 }
1844
1845 ast_channel_lock(session->channel);
1847 ast_channel_unlock(session->channel);
1848 ast_raw_answer(session->channel);
1849
1850 ast_debug(3, "INVITE with Replaces being attempted. '%s' --> '%s'\n",
1851 ast_channel_name(session->channel), ast_channel_name(invite.channel));
1852
1853 /* Unhold the channel now, as later we are not having access to it anymore */
1854 ast_queue_unhold(session->channel);
1856
1857 if (!invite.bridge) {
1858 struct ast_channel *chan = session->channel;
1859
1860 /*
1861 * This will use a synchronous task but we aren't operating in
1862 * the serializer at this point in time, so it won't deadlock.
1863 */
1864 if (!ast_channel_move(invite.channel, chan)) {
1865 /*
1866 * We can't directly use session->channel because ast_channel_move()
1867 * does a masquerade which changes session->channel to a different
1868 * channel. To ensure we work on the right channel we store a
1869 * pointer locally before we begin so it remains valid.
1870 */
1871 ast_hangup(chan);
1872 } else {
1873 response = AST_CAUSE_FAILURE;
1874 }
1875 } else {
1876 if (ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL,
1878 response = AST_CAUSE_FAILURE;
1879 }
1880 }
1881
1882 ast_channel_unref(invite.channel);
1883 ao2_cleanup(invite.bridge);
1884
1885 if (!response) {
1886 /*
1887 * On success we cannot use session->channel in the debug message.
1888 * This thread either no longer has a ref to session->channel or
1889 * session->channel is no longer the original channel.
1890 */
1891 ast_debug(3, "INVITE with Replaces successfully completed.\n");
1892 } else {
1893 ast_debug(3, "INVITE with Replaces failed on channel '%s', hanging up with cause '%d'\n",
1894 ast_channel_name(session->channel), response);
1895 ast_channel_lock(session->channel);
1896 ast_channel_hangupcause_set(session->channel, response);
1897 ast_channel_unlock(session->channel);
1898 ast_hangup(session->channel);
1899 }
1900
1901 return 1;
1902
1903inv_replace_failed:
1904 if (session->inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
1905 ast_debug(3, "INVITE with Replaces failed on channel '%s', sending response of '%d'\n",
1906 ast_channel_name(session->channel), response);
1907 session->defer_terminate = 1;
1908 ast_hangup(session->channel);
1909
1910 if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS
1911 && packet) {
1913 }
1914 } else {
1915 ast_debug(3, "INVITE with Replaces in-dialog on channel '%s', hanging up\n",
1916 ast_channel_name(session->channel));
1917 ast_queue_hangup(session->channel);
1918 }
1919
1920 return 1;
1921}
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:1947
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition: bridge.h:594
#define AST_CAUSE_FAILURE
Definition: causes.h:150
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2510
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1180
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:1169
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:10671
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1254
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3008
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:2659
@ AST_STATE_RING
Definition: channelstate.h:40
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7359
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:2179
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:739

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 1923 of file res_pjsip_refer.c.

1924{
1925 pjsip_generic_string_hdr *refer_to;
1926 char *uri;
1927 size_t uri_size;
1928 pjsip_uri *target;
1929 pjsip_sip_uri *target_uri;
1931 pjsip_param *replaces;
1932 int response;
1933
1934 static const pj_str_t str_refer_to = { "Refer-To", 8 };
1935 static const pj_str_t str_refer_to_s = { "r", 1 };
1936 static const pj_str_t str_replaces = { "Replaces", 8 };
1937
1938 if (!session->channel) {
1939 /* No channel to refer. Likely because the call was just hung up. */
1940 pjsip_dlg_respond(session->inv_session->dlg, rdata, 404, NULL, NULL, NULL);
1941 ast_debug(3, "Received a REFER on a session with no channel from endpoint '%s'.\n",
1943 return 0;
1944 }
1945
1946 if (!session->endpoint->allowtransfer) {
1947 pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
1948 ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
1950 return 0;
1951 }
1952
1953 /* A Refer-To header is required */
1954 refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL);
1955 if (!refer_to) {
1956 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1957 ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
1959 return 0;
1960 }
1961
1962 /* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri
1963 * as pjsip_parse_uri require a NULL terminated uri
1964 */
1965
1966 uri_size = pj_strlen(&refer_to->hvalue) + 1;
1967 uri = ast_alloca(uri_size);
1968 ast_copy_pj_str(uri, &refer_to->hvalue, uri_size);
1969
1970 target = pjsip_parse_uri(rdata->tp_info.pool, uri, uri_size - 1, 0);
1971
1972 if (!target
1973 || (!PJSIP_URI_SCHEME_IS_SIP(target)
1974 && !PJSIP_URI_SCHEME_IS_SIPS(target))) {
1975
1976 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1977 ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n",
1978 uri, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
1979 return 0;
1980 }
1981 target_uri = pjsip_uri_get_uri(target);
1982
1983 /* Set up REFER progress subscription if requested/possible */
1984 if (refer_progress_alloc(session, rdata, &progress)) {
1985 pjsip_dlg_respond(session->inv_session->dlg, rdata, 500, NULL, NULL, NULL);
1986 ast_debug(3, "Could not set up subscription for REFER on channel '%s' from endpoint '%s'\n",
1988 return 0;
1989 }
1990
1991 replaces = pjsip_param_find(&target_uri->header_param, &str_replaces);
1992 if (!replaces) {
1993 replaces = pjsip_param_find(&target_uri->other_param, &str_replaces);
1994 }
1995
1996 /* Determine if this is handled externally or an attended or blind transfer */
1997 if (session->transferhandling_ari) {
1998 response = refer_incoming_ari_request(session, rdata, target_uri, replaces, progress);
1999 } else if (replaces) {
2000 response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
2001 } else {
2002 response = refer_incoming_blind_request(session, rdata, target_uri, progress);
2003 }
2004
2005 if (!progress) {
2006 /* The transferer has requested no subscription, so send a final response immediately */
2007 pjsip_tx_data *tdata;
2008 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
2009 const pj_str_t str_false = { "false", 5 };
2010 pjsip_hdr *hdr;
2011
2012 ast_debug(3, "Progress monitoring not requested for REFER on channel '%s' from endpoint '%s', sending immediate response of '%d'\n",
2013 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), response);
2014
2015 if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, response, NULL, &tdata) != PJ_SUCCESS) {
2016 pjsip_dlg_respond(session->inv_session->dlg, rdata, response, NULL, NULL, NULL);
2017 return 0;
2018 }
2019
2020 hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
2021 pjsip_msg_add_hdr(tdata->msg, hdr);
2022
2023 pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2024 } else if (response != 200) {
2025 /* Since this failed we can send a final NOTIFY now and terminate the subscription */
2026 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
2027
2028 if (notification) {
2029 /* The refer_progress_notify function will call ao2_cleanup on this for us */
2030 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
2031 ao2_cleanup(notification);
2032 }
2033 }
2034 }
2035
2036 return 0;
2037}
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(), 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, 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 2039 of file res_pjsip_refer.c.

2040{
2041 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
2043 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_invite_method)) {
2045 } else {
2046 return 0;
2047 }
2048}
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 1130 of file res_pjsip_refer.c.

1130 {
1131 RAII_VAR(struct ast_str *, refer_to_str, ast_str_create(PJSIP_MAX_URL_SIZE), ast_free_ptr);
1132 const pj_str_t REFER_TO = { "Refer-To", 8 };
1133 pjsip_generic_string_hdr *refer_to_hdr;
1134 pjsip_dialog *dlg;
1135 struct refer_data *refer_data;
1136 pjsip_uri *parsed_uri;
1137 pjsip_sip_uri *refer_to_uri;
1138
1139 /*
1140 * If this is a request in response to a 401/407 Unauthorized challenge, the
1141 * Refer-To URI has been rewritten already, so don't attempt to re-write it again.
1142 * Checking for presence of the Authorization header is not an ideal solution. We do this because
1143 * there exists some race condition where this dialog is not the same as the one used
1144 * to send the original request in which case we don't have the correct refer_data.
1145 */
1146 if (!refer_to_str
1147 || pjsip_msg_find_hdr(tdata->msg, PJSIP_H_AUTHORIZATION, NULL)
1148 || !(dlg = pjsip_tdata_get_dlg(tdata))
1149 || !(refer_data = pjsip_dlg_get_mod_data(dlg, refer_out_of_dialog_module.id))
1150 || !refer_data->to_self
1151 || !(parsed_uri = get_refer_to_uri(tdata))) {
1152 goto out;
1153 }
1154 refer_to_uri = pjsip_uri_get_uri(parsed_uri);
1155 ast_sip_rewrite_uri_to_local(refer_to_uri, tdata);
1156
1157 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, parsed_uri, ast_str_buffer(refer_to_str), ast_str_size(refer_to_str));
1158 refer_to_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL);
1159 pj_strdup2(tdata->pool, &refer_to_hdr->hvalue, ast_str_buffer(refer_to_str));
1160
1161out:
1162 return PJ_SUCCESS;
1163}
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:605
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 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 1182 of file res_pjsip_refer.c.

1182 {
1183 struct refer_out_of_dialog *data = obj;
1184
1185 if (data->dlg) {
1186 /* ast_sip_push_task_wait_servant should not be called in a destructor,
1187 * however in this case it seems to be fine.
1188 */
1190 }
1191}
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c: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 2083 of file res_pjsip_refer.c.

2084{
2085 if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method)
2086 || !session->channel
2087 || session->inv_session->state != PJSIP_INV_STATE_NULL) {
2088 return;
2089 }
2090
2091 ast_channel_lock(session->channel);
2092 add_header_from_channel_var(session->channel, "SIPREPLACESHDR", "Replaces", tdata);
2093 add_header_from_channel_var(session->channel, "SIPREFERREDBYHDR", "Referred-By", tdata);
2094 ast_channel_unlock(session->channel);
2095}
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 121 of file res_pjsip_refer.c.

122{
123 struct ast_refer_params *params = obj;
124
125 for (int i = 0; i < AST_VECTOR_SIZE(params); ++i) {
126 struct ast_refer_param param = AST_VECTOR_GET(params, i);
127 ast_free((char *) param.param_name);
128 ast_free((char *) param.param_value);
129 }
130}
const char * param_value
Definition: refer.h:83
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

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 502 of file res_pjsip_refer.c.

503{
504 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
505 pjsip_generic_string_hdr *refer_sub = NULL;
506 const pj_str_t str_true = { "true", 4 };
507 pjsip_hdr hdr_list;
508 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
509
510 *progress = NULL;
511
512 /* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */
513 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
514 if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4))) {
515 return 0;
516 }
517
518 if (!(*progress = ao2_alloc(sizeof(struct refer_progress), refer_progress_destroy))) {
519 return -1;
520 }
521
522 ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
524
525 (*progress)->refer_blind_progress = session->endpoint->refer_blind_progress;
526
527 (*progress)->framehook = -1;
528
529 /* Create name with seq number appended. */
530 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/refer/%s",
532
533 if (!((*progress)->serializer = ast_sip_create_serializer(tps_name))) {
534 goto error;
535 }
536
537 /* Create the implicit subscription for monitoring of this transfer */
538 if (pjsip_xfer_create_uas(session->inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
539 goto error;
540 }
541
542 /* To prevent a potential deadlock we need the dialog so we can lock/unlock */
543 (*progress)->dlg = session->inv_session->dlg;
544 /* We also need to make sure it stays around until we're done with it */
545 pjsip_dlg_inc_session((*progress)->dlg, &refer_progress_module);
546
547
548 /* Associate the REFER progress structure with the subscription */
549 ao2_ref(*progress, +1);
550 pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
551
552 pj_list_init(&hdr_list);
553 if (refer_sub) {
554 pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->inv_session->dlg->pool, &str_refer_sub, &str_true);
555
556 pj_list_push_back(&hdr_list, hdr);
557 }
558
559 /* Accept the REFER request */
560 ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress);
561 pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
562
563 return 0;
564
565error:
567 *progress = NULL;
568 return -1;
569}
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).
Definition: taskprocessor.h:61
int error(const char *format,...)
Definition: utils/frame.c:999

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(), NULL, refer_progress::rdata, refer_progress_destroy(), refer_progress_evsub_cb, refer_progress_module, 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 248 of file res_pjsip_refer.c.

250{
251 struct refer_progress *progress = data;
252 struct ast_bridge_blob *enter_blob;
253 struct refer_progress_notification *notification;
254 struct ast_channel *chan;
255
257 ao2_ref(progress, -1);
258 return;
259 }
260
262 /* Don't care */
263 return;
264 }
265
266 enter_blob = stasis_message_data(message);
267 if (strcmp(enter_blob->channel->base->uniqueid, progress->transferee)) {
268 /* Don't care */
269 return;
270 }
271
272 if (!progress->transfer_data->completed) {
273 /* We can't act on this message because the transfer_channel_data doesn't show that
274 * the transfer is ready to progress */
275 return;
276 }
277
278 /* OMG the transferee is joining a bridge. His call got answered! */
279 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
280 if (notification) {
281 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
282 ao2_cleanup(notification);
283 }
284 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
285 }
286
287 chan = ast_channel_get_by_name(progress->transferee);
288 if (!chan) {
289 /* The channel is already gone */
290 return;
291 }
292
293 ast_channel_lock(chan);
294 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as it has joined a bridge\n",
295 ast_channel_name(chan));
296 ast_framehook_detach(chan, progress->framehook);
297 ast_channel_unlock(chan);
298
299 ast_channel_unref(chan);
300}
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition: channel.c:1397
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
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:1201
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:998
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_message_type(), 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 468 of file res_pjsip_refer.c.

469{
470 struct refer_progress *progress = obj;
471
472 if (progress->bridge_sub) {
473 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
474 }
475
476 if (progress->dlg) {
477 /*
478 * Although the dlg session count was incremented in a pjsip servant
479 * thread, there's no guarantee that the last thread to unref this progress
480 * object was one. Before we decrement, we need to make sure that this
481 * is either a servant thread or that we push the decrement to a
482 * serializer that is one.
483 *
484 * Because pjsip_dlg_dec_session requires the dialog lock, we don't want
485 * to wait on the task to complete if we had to push it to a serializer.
486 */
488 pjsip_dlg_dec_session(progress->dlg, &refer_progress_module);
489 } else {
491 }
492 }
493
494 ao2_cleanup(progress->transfer_data);
495 ao2_cleanup(progress->ari_state);
496
497 ast_free(progress->transferee);
499}
int ast_sip_thread_is_servant(void)
Determine if the current thread is a SIP servant thread.
Definition: res_pjsip.c:2310
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, 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 303 of file res_pjsip_refer.c.

304{
305 struct refer_progress *progress = data;
306 struct refer_progress_notification *notification = NULL;
307
308 /* We only care about frames *to* the channel */
309 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
310 return f;
311 }
312
313 /* If the completed flag hasn't been raised, skip this pass. */
314 if (!progress->transfer_data->completed) {
315 return f;
316 }
317
318 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
319 if (f->frametype == AST_FRAME_VOICE && !progress->subclass) {
320 /* Media is passing without progress, this means the call has been answered */
321 progress->subclass = AST_CONTROL_ANSWER;
322 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
323 } else if (f->frametype == AST_FRAME_CONTROL) {
324 /* Based on the control frame being written we can send a NOTIFY advising of the progress */
326 /* Don't set progress->subclass; an ANSWER can still follow */
327 notification = refer_progress_notification_alloc(progress, 180, PJSIP_EVSUB_STATE_ACTIVE);
328 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
329 progress->subclass = f->subclass.integer;
330 notification = refer_progress_notification_alloc(progress, 486, PJSIP_EVSUB_STATE_TERMINATED);
331 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
332 progress->subclass = f->subclass.integer;
333 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
334 } else if (f->subclass.integer == AST_CONTROL_PROGRESS) {
335 /* Don't set progress->subclass; an ANSWER can still follow */
336 notification = refer_progress_notification_alloc(progress, 183, PJSIP_EVSUB_STATE_ACTIVE);
337 } else if (f->subclass.integer == AST_CONTROL_PROCEEDING) {
338 /* Don't set progress->subclass; an ANSWER can still follow */
339 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
340 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
341 progress->subclass = f->subclass.integer;
342 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
343 }
344 }
345
346 /* If a notification is due to be sent push it to the thread pool */
347 if (notification) {
348 /* If the subscription is being terminated we don't need the frame hook any longer */
349 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
350 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
351 ast_channel_name(chan));
352 ast_framehook_detach(chan, progress->framehook);
353 }
354
355 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
356 ao2_cleanup(notification);
357 }
358 }
359
360 return f;
361}
@ AST_FRAME_VOICE
@ AST_CONTROL_RING
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_BUSY
@ 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 416 of file res_pjsip_refer.c.

417{
418 struct refer_progress *progress = data;
419 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
420
421 if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
422 ao2_cleanup(notification);
423 }
424
425 if (progress->bridge_sub) {
426 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
427 }
428
430}

References ao2_cleanup, ast_sip_push_task(), refer_progress_notification_alloc(), refer_progress_notify(), 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 149 of file res_pjsip_refer.c.

151{
152 struct refer_progress_notification *notification = ao2_alloc(sizeof(*notification), refer_progress_notification_destroy);
153
154 if (!notification) {
155 return NULL;
156 }
157
158 ao2_ref(progress, +1);
159 notification->progress = progress;
160 notification->response = response;
161 notification->state = state;
162
163 return notification;
164}
static void refer_progress_notification_destroy(void *obj)
Destructor for REFER Progress notification structure.
struct refer_progress * progress
Refer progress structure to send notification on.

References ao2_alloc, ao2_ref, NULL, refer_progress_notification::progress, refer_progress_notification_destroy(), refer_progress_notification::response, state, 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 133 of file res_pjsip_refer.c.

134{
135 struct refer_progress_notification *notification = obj;
136
137 ao2_cleanup(notification->progress);
138}

References ao2_cleanup, and refer_progress_notification::progress.

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 195 of file res_pjsip_refer.c.

196{
197 RAII_VAR(struct refer_progress_notification *, notification, data, ao2_cleanup);
198 pjsip_evsub *sub;
199 pjsip_tx_data *tdata;
200
201 pjsip_dlg_inc_lock(notification->progress->dlg);
202
203 /* If the subscription has already been terminated we can't send a notification */
204 if (!(sub = notification->progress->sub)) {
205 ast_debug(3, "Not sending NOTIFY of response '%d' and state '%u' on progress monitor '%p' as subscription has been terminated\n",
206 notification->response, notification->state, notification->progress);
207 pjsip_dlg_dec_lock(notification->progress->dlg);
208 return 0;
209 }
210
211 /* Send a deferred initial 100 Trying SIP frag NOTIFY if we haven't already. */
212 if (!notification->progress->sent_100) {
213 notification->progress->sent_100 = 1;
214 if (notification->response != 100) {
215 ast_debug(3, "Sending initial 100 Trying NOTIFY for progress monitor '%p'\n",
216 notification->progress);
217 if (pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) {
218 pjsip_xfer_send_request(sub, tdata);
219 }
220 }
221 }
222
223 ast_debug(3, "Sending NOTIFY with response '%d' and state '%u' on subscription '%p' and progress monitor '%p'\n",
224 notification->response, notification->state, sub, notification->progress);
225
226 /* Actually send the notification */
227 if (pjsip_xfer_notify(sub, notification->state, notification->response, NULL, &tdata) == PJ_SUCCESS) {
228 pjsip_xfer_send_request(sub, tdata);
229 }
230
231
232 if (notification->progress->ari_state) {
233 struct transfer_ari_state *ari_state = notification->progress->ari_state;
234 if (ari_state->transferer && notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
236 /* Gave the ref to the pushed task. */
237 ari_state->transferer = NULL;
238 }
239 }
240 ari_notify(ari_state);
241 }
242
243 pjsip_dlg_dec_lock(notification->progress->dlg);
244
245 return 0;
246}
struct ast_sip_session * transferer
A deferred session used by the ARI only mode.

References ao2_cleanup, ari_notify(), ast_debug, ast_sip_push_task(), defer_termination_cancel_task(), NULL, RAII_VAR, ast_sip_session::serializer, sub, and transfer_ari_state::transferer.

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 442 of file res_pjsip_refer.c.

443{
444 struct refer_progress *progress = pjsip_evsub_get_mod_data(sub, refer_progress_module.id);
445
446 /*
447 * If being destroyed, remove the progress object from the subscription
448 * and release the reference it had.
449 */
450 if (progress && (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)) {
451 pjsip_evsub_set_mod_data(progress->sub, refer_progress_module.id, NULL);
452 progress->sub = NULL;
454 }
455}

References ao2_cleanup, NULL, refer_progress_module, and sub.

◆ refer_send()

static int refer_send ( void *  data)
static

Definition at line 1335 of file res_pjsip_refer.c.

1336{
1337 struct refer_data *rdata = data; /* The caller holds a reference */
1338 pjsip_tx_data *tdata;
1339 pjsip_evsub *sub;
1340 pj_str_t tmp;
1341 char refer_to_str[PJSIP_MAX_URL_SIZE];
1342 char disp_name_escaped[128];
1343 struct refer_out_of_dialog *refer;
1344 struct pjsip_evsub_user xfer_cb;
1345 RAII_VAR(char *, uri, NULL, ast_free);
1346 RAII_VAR(char *, tmp_str, NULL, ast_free);
1347 RAII_VAR(char *, display_name, NULL, ast_free);
1348 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1349 RAII_VAR(struct ast_sip_endpoint *, refer_to_endpoint, NULL, ao2_cleanup);
1350
1351 endpoint = ast_sip_get_endpoint(rdata->destination, 1, &uri);
1352 if (!endpoint) {
1354 "PJSIP REFER - Could not find endpoint '%s' and no default outbound endpoint configured\n",
1355 rdata->destination);
1356 return -1;
1357 }
1358 ast_debug(3, "Request URI: %s\n", uri);
1359
1360 refer_to_endpoint = ast_sip_get_endpoint(rdata->refer_to, 0, &tmp_str);
1361 if (!tmp_str) {
1362 ast_log(LOG_WARNING, "PJSIP REFER - Refer to not a valid resource identifier or SIP URI\n");
1363 return -1;
1364 }
1365 if (!(refer = ao2_alloc(sizeof(struct refer_out_of_dialog), refer_out_of_dialog_destroy))) {
1366 ast_log(LOG_ERROR, "PJSIP REFER - Could not allocate resources.\n");
1367 return -1;
1368 }
1369 /* The dialog will be terminated in the subscription event callback
1370 * when the subscription has terminated. */
1372 refer->dlg = ast_sip_create_dialog_uac(endpoint, uri, NULL);
1373 if (!refer->dlg) {
1374 ast_log(LOG_WARNING, "PJSIP REFER - Could not create dialog\n");
1375 ao2_cleanup(refer);
1376 return -1;
1377 }
1378 ast_sip_dialog_set_endpoint(refer->dlg, endpoint);
1379
1380 pj_bzero(&xfer_cb, sizeof(xfer_cb));
1381 xfer_cb.on_evsub_state = &refer_client_on_evsub_state;
1382 if (pjsip_xfer_create_uac(refer->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
1383 ast_log(LOG_WARNING, "PJSIP REFER - Could not create uac\n");
1384 ao2_cleanup(refer);
1385 return -1;
1386 }
1387
1388 display_name = ast_refer_get_var_and_unlink(rdata->refer, "display_name");
1389 if (display_name) {
1390 ast_escape_quoted(display_name, disp_name_escaped, sizeof(disp_name_escaped));
1391 snprintf(refer_to_str, sizeof(refer_to_str), "\"%s\" <%s>", disp_name_escaped, tmp_str);
1392 } else {
1393 snprintf(refer_to_str, sizeof(refer_to_str), "%s", tmp_str);
1394 }
1395
1396 /* refer_out_of_dialog_module requires a reference to dlg
1397 * which will be released in refer_client_on_evsub_state()
1398 * when the implicit REFER subscription terminates */
1399 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, refer);
1400 if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, refer_to_str), &tdata) != PJ_SUCCESS) {
1401 ast_log(LOG_WARNING, "PJSIP REFER - Could not create request\n");
1402 goto failure;
1403 }
1404
1405 if (refer_to_endpoint && rdata->to_self) {
1406 pjsip_dlg_add_usage(refer->dlg, &refer_out_of_dialog_module, rdata);
1407 }
1408
1409 ast_sip_update_to_uri(tdata, uri);
1410 ast_sip_update_from(tdata, rdata->from);
1411
1412 /*
1413 * This copies any headers found in the refer's variables to
1414 * tdata.
1415 */
1416 vars_to_headers(rdata->refer, tdata);
1417 ast_debug(1, "Sending REFER to '%s' (via endpoint %s) from '%s'\n",
1418 rdata->destination, ast_sorcery_object_get_id(endpoint), rdata->from);
1419
1420 if (pjsip_xfer_send_request(sub, tdata) == PJ_SUCCESS) {
1421 return 0;
1422 }
1423
1424failure:
1425 ao2_cleanup(refer);
1426 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1427 pjsip_evsub_terminate(sub, PJ_FALSE);
1428 return -1;
1429}
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:3249
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:964
int ast_sip_update_from(pjsip_tx_data *tdata, char *from)
Overwrite fields in the outbound 'From' header.
Definition: res_pjsip.c:3383
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:3323
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:781

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 1165 of file res_pjsip_refer.c.

1166{
1167 struct refer_out_of_dialog *data = obj;
1168
1169 /* This is why we keep the dialog on the subscription. When the subscription
1170 * is destroyed, there is no guarantee that the underlying dialog is ready
1171 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1172 * either. The dialog could be destroyed before our subscription is. We fix
1173 * this problem by keeping a reference to the dialog until it is time to
1174 * destroy the subscription.
1175 */
1176 pjsip_dlg_dec_session(data->dlg, &refer_out_of_dialog_module);
1177 data->dlg = NULL;
1178
1179 return 0;
1180}

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 622 of file res_pjsip_refer.c.

623{
624 struct ast_sip_session *session = data;
625
627 ao2_ref(session, -1);
628 return 0;
629}

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 1431 of file res_pjsip_refer.c.

1432{
1433 struct refer_data *rdata;
1434 int res;
1435
1437 ast_log(LOG_ERROR, "SIP REFER - a 'To' URI must be specified\n");
1438 return -1;
1439 }
1440
1441 rdata = refer_data_create(refer);
1442 if (!rdata) {
1443 return -1;
1444 }
1445
1447 ao2_ref(rdata, -1);
1448
1449 return res;
1450}
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 109 of file res_pjsip_refer.c.

110{
111 struct transfer_ari_state *state = obj;
112
113 ao2_cleanup(state->transferer);
114 ao2_cleanup(state->other_session);
115 ast_channel_cleanup(state->transferer_chan);
116 ast_free(state->referred_by);
117 ast_free(state->protocol_id);
118 ao2_cleanup(state->params);
119}

References ao2_cleanup, ast_channel_cleanup, and ast_free.

Referenced by refer_incoming_ari_request().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2133 of file res_pjsip_refer.c.

2134{
2139
2140 return 0;
2141}
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:133
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
Definition: pjsip_session.c:63

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 1082 of file res_pjsip_refer.c.

1083{
1084 const char *name;
1085 const char *value;
1087
1088 for (iter = ast_refer_var_iterator_init(refer);
1091 if (!is_refer_var_blocked(name)) {
1092 ast_sip_add_header(tdata, name, value);
1093 }
1094 }
1096
1097 return PJSIP_SC_OK;
1098}
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 650 of file res_pjsip_refer.c.

651{
652 int response;
653
654 response = 503;
655 switch (xfer_code) {
657 response = 400;
658 break;
660 response = 403;
661 break;
663 response = 500;
664 break;
666 response = 200;
667 break;
668 }
669 return response;
670}
@ AST_BRIDGE_TRANSFER_NOT_PERMITTED
Definition: bridge.h:1106
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1104
@ AST_BRIDGE_TRANSFER_INVALID
Definition: bridge.h:1108
@ AST_BRIDGE_TRANSFER_FAIL
Definition: bridge.h:1110

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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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 2149 of file res_pjsip_refer.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2149 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 1106 of file res_pjsip_refer.c.

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 458 of file res_pjsip_refer.c.

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 103 of file res_pjsip_refer.c.

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:3339
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 2097 of file res_pjsip_refer.c.

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 1452 of file res_pjsip_refer.c.

Referenced by ast_refer_send(), and load_module().