Asterisk - The Open Source Telephony Project GIT-master-a358458
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...
 

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...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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 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_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 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 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 837 of file res_pjsip_refer.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1865 of file res_pjsip_refer.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

1781{
1782 const char *var_value;
1783 pj_str_t pj_header_name;
1784 pjsip_hdr *header;
1785
1786 var_value = pbx_builtin_getvar_helper(chan, var_name);
1787 if (ast_strlen_zero(var_value)) {
1788 return;
1789 }
1790
1791 pj_cstr(&pj_header_name, header_name);
1792 header = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_header_name, NULL);
1793 if (header) {
1794 return;
1795 }
1796 ast_sip_add_header(tdata, header_name, var_value);
1797}
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().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1865 of file res_pjsip_refer.c.

◆ defer_termination_cancel_task()

static int defer_termination_cancel_task ( void *  data)
static

Definition at line 516 of file res_pjsip_refer.c.

517{
518 struct ast_sip_session *session = data;
519
522 ao2_ref(session, -1);
523 return 0;
524}
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().

◆ dlg_releaser_task()

static int dlg_releaser_task ( void *  data)
static

Definition at line 348 of file res_pjsip_refer.c.

348 {
349 pjsip_dlg_dec_session((pjsip_dialog *)data, &refer_progress_module);
350 return 0;
351}
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 1000 of file res_pjsip_refer.c.

1001{
1002 const pj_str_t REFER_TO = { "Refer-To", 8 };
1003 pjsip_generic_string_hdr *refer_to;
1004 pjsip_uri *parsed_uri;
1005
1006 if (!(refer_to = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL))
1007 || !(parsed_uri = pjsip_parse_uri(tdata->pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0))
1008 || (!PJSIP_URI_SCHEME_IS_SIP(parsed_uri) && !PJSIP_URI_SCHEME_IS_SIPS(parsed_uri))) {
1009 return NULL;
1010 }
1011
1012 return parsed_uri;
1013}

References NULL.

Referenced by refer_on_tx_request().

◆ invite_replaces()

static int invite_replaces ( void *  data)
static

Task for invite replaces.

Definition at line 1507 of file res_pjsip_refer.c.

1508{
1509 struct invite_replaces *invite = data;
1510
1511 if (!invite->session->channel) {
1512 return -1;
1513 }
1514
1516 invite->channel = invite->session->channel;
1517
1519 return 0;
1520}
struct ast_bridge * ast_bridge_transfer_acquire_bridge(struct ast_channel *chan)
Acquire the channel's bridge for transfer purposes.
Definition: bridge.c:4408
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2947
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 932 of file res_pjsip_refer.c.

933{
934 int i;
935
936 /* Don't block the Max-Forwards header because the user can override it */
937 static const char *hdr[] = {
938 "To",
939 "From",
940 "Via",
941 "Route",
942 "Contact",
943 "Call-ID",
944 "CSeq",
945 "Allow",
946 "Content-Length",
947 "Content-Type",
948 "Request-URI",
949 };
950
951 for (i = 0; i < ARRAY_LEN(hdr); ++i) {
952 if (!strcasecmp(name, hdr[i])) {
953 /* Block addition of this header. */
954 return 1;
955 }
956 }
957 return 0;
958}
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 1819 of file res_pjsip_refer.c.

1820{
1821 const pj_str_t str_norefersub = { "norefersub", 10 };
1822
1823 pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint());
1824 pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint());
1825
1826 if (ast_sip_get_norefersub()) {
1827 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub);
1828 }
1829
1832 }
1833
1835 if (!refer_serializer) {
1838 }
1839
1843
1845
1847}
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:464
@ 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:490
int ast_refer_tech_register(const struct ast_refer_tech *tech)
Register a refer technology.
Definition: refer.c:446
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:342

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

483{
484 struct refer_attended *attended;
485
486 attended = ao2_alloc_options(sizeof(*attended), refer_attended_destroy,
488 if (!attended) {
489 return NULL;
490 }
491
492 ao2_ref(transferer, +1);
493 attended->transferer = transferer;
498
499 if (progress) {
500 ao2_ref(progress, +1);
501 attended->progress = progress;
502 }
503
504 return attended;
505}
@ 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.
Definition: dsp.c:117
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 469 of file res_pjsip_refer.c.

470{
471 struct refer_attended *attended = obj;
472
473 ao2_cleanup(attended->transferer);
476 ao2_cleanup(attended->progress);
477}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969

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

559{
560 struct refer_attended *attended = data;
561 int response;
562 int (*task_cb)(void *data);
563
564 if (attended->transferer_second->channel) {
565 ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
568
570 attended->transferer_chan,
571 attended->transferer_second->channel));
572
573 ast_debug(3, "Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
576 response);
577 } else {
578 ast_debug(3, "Received REFER request on channel '%s' but other channel has gone.\n",
580 response = 603;
581 }
582
583 if (attended->progress) {
584 struct refer_progress_notification *notification;
585
586 notification = refer_progress_notification_alloc(attended->progress, response,
587 PJSIP_EVSUB_STATE_TERMINATED);
588 if (notification) {
589 if (ast_sip_push_task(attended->progress->serializer, refer_progress_notify, notification)) {
590 ao2_cleanup(notification);
591 }
592 }
593 }
594
595 if (response == 200) {
597 } else {
599 }
601 task_cb, attended->transferer)) {
602 /* Gave the ref to the pushed task. */
603 attended->transferer = NULL;
604 } else {
605 /* Do this anyway even though it is the wrong serializer. */
607 }
608
609 ao2_ref(attended, -1);
610 return 0;
611}
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
Definition: bridge.c:4677
const char * ast_channel_name(const struct ast_channel *chan)
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
#define ast_debug(level,...)
Log a DEBUG message.
static int xfer_response_code2sip(enum ast_transfer_result xfer_code)
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.
static int defer_termination_cancel_task(void *data)
static int session_end_if_deferred_task(void *data)
struct ast_taskprocessor * serializer
REFER Progress notification structure.
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 630 of file res_pjsip_refer.c.

632{
633 struct refer_blind *refer = user_data_wrapper->data;
634 pjsip_generic_string_hdr *referred_by;
635
636 static const pj_str_t str_referred_by = { "Referred-By", 11 };
637 static const pj_str_t str_referred_by_s = { "b", 1 };
638 const char *get_xfrdata;
639
640 pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
641
642 if (refer->progress && !refer->attended && !refer->progress->refer_blind_progress) {
643 /* If blind transfer and endpoint doesn't want to receive all the progress details */
645 PJSIP_EVSUB_STATE_TERMINATED);
646
647 if (notification) {
648 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
649 ao2_cleanup(notification);
650 }
651 }
652 } else if (refer->progress) {
653 /* If attended transfer and progress monitoring is being done attach a frame hook so we can monitor it */
654 struct ast_framehook_interface hook = {
656 .event_cb = refer_progress_framehook,
658 .data = refer->progress,
659 .disable_inheritance = 1,
660 };
661
663 if (!refer->progress->transferee) {
665 PJSIP_EVSUB_STATE_TERMINATED);
666
667 ast_log(LOG_WARNING, "Could not copy channel name '%s' during transfer - assuming success\n",
668 ast_channel_name(chan));
669
670 if (notification) {
671 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
672 ao2_cleanup(notification);
673 }
674 }
675 }
676
677 /* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
678 ao2_ref(user_data_wrapper, +1);
679 refer->progress->transfer_data = user_data_wrapper;
680
681 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
682 ao2_ref(refer->progress, +1);
683
684 /* If we can't attach a frame hook for whatever reason send a notification of success immediately */
685 ast_channel_lock(chan);
686 refer->progress->framehook = ast_framehook_attach(chan, &hook);
687 ast_channel_unlock(chan);
688 if (refer->progress->framehook < 0) {
690 PJSIP_EVSUB_STATE_TERMINATED);
691
692 ast_log(LOG_WARNING, "Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
693 ast_channel_name(chan));
694
695 if (notification) {
696 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
697 ao2_cleanup(notification);
698 }
699 }
700
701 ao2_cleanup(refer->progress);
702 }
703
704 /* We need to bump the reference count for the stasis subscription */
705 ao2_ref(refer->progress, +1);
706 /* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
707 * detect if the transfer target has answered the call
708 */
710 if (!refer->progress->bridge_sub) {
712 PJSIP_EVSUB_STATE_TERMINATED);
713
714 ast_log(LOG_WARNING, "Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success\n",
715 ast_channel_name(chan));
716
717 if (notification) {
718 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
719 ao2_cleanup(notification);
720 }
721 }
722
723 ast_channel_lock(chan);
725 ast_channel_unlock(chan);
726
727 ao2_cleanup(refer->progress);
728 } else {
732 }
733 }
734
735 pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL));
736
737 ast_channel_lock(chan);
738 if ((get_xfrdata = pbx_builtin_getvar_helper(chan, "GET_TRANSFERRER_DATA"))) {
739 get_xfrdata = ast_strdupa(get_xfrdata);
740 }
741 ast_channel_unlock(chan);
742 if (!ast_strlen_zero(get_xfrdata)) {
743 const pjsip_msg * msg = refer->rdata->msg_info.msg;
744 const struct pjsip_hdr *end = &msg->hdr;
745 struct pjsip_hdr *hdr = end->next;
746 struct ast_str *pbxvar = ast_str_create(64); /* initial buffer for variable name, extended on demand */
747 char buf[4096]; /* should be enough for one header value */
748 const char *prefix = get_xfrdata;
749
750 /* The '*' alone matches all headers. */
751 if (!strcmp(prefix, "*")) {
752 prefix = "";
753 }
754 if (pbxvar) {
755 for (; hdr != end; hdr = hdr->next) {
756 if (!pj_strnicmp2(&hdr->name, prefix, strlen(prefix))) {
757 const int hdr_name_strlen = pj_strlen(&hdr->name);
758 const int hdr_name_bytes = hdr_name_strlen + 1; /* +1 for string NULL terminator */
759 char hdr_name[hdr_name_bytes];
760 int len;
761 char *value_str;
762
763 ast_copy_pj_str(hdr_name, &hdr->name, hdr_name_bytes);
764 len = pjsip_hdr_print_on(hdr, buf, sizeof(buf) - 1);
765 if (len < 0) {
766 /* ignore too long headers */
767 ast_log(LOG_WARNING, "Could not store header '%s' from transfer on channel '%s' - too long text\n", hdr_name, ast_channel_name(chan));
768 continue;
769 }
770 buf[len] = '\0';
771
772 /* Get value - remove header name (before ':') from buf and trim blanks. */
773 value_str = strchr(buf, ':');
774 if (!value_str) {
775 /* Ignore header without value */
776 continue;
777 }
778 value_str = ast_strip(value_str + 1); /* +1 to get string right after the ':' delimiter (i.e. header value) */
779
780 ast_str_set(&pbxvar, -1, "~HASH~TRANSFER_DATA~%.*s~", hdr_name_strlen, hdr_name);
781 pbx_builtin_setvar_helper(chan, ast_str_buffer(pbxvar), value_str);
782 ast_debug(5, "On channel '%s' set TRANSFER_DATA variable '%s' to value '%s' \n", ast_channel_name(chan), hdr_name, value_str);
783 }
784 }
785 ast_free(pbxvar);
786 } else {
787 ast_log(LOG_ERROR, "Channel '%s' failed to allocate buffer for TRANSFER_DATA variable\n", ast_channel_name(chan));
788 }
789 }
790
791 referred_by = pjsip_msg_find_hdr_by_names(refer->rdata->msg_info.msg,
792 &str_referred_by, &str_referred_by_s, NULL);
793 if (referred_by) {
794 size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
795 char *uri = ast_alloca(uri_size);
796
797 ast_copy_pj_str(uri, &referred_by->hvalue, uri_size);
798 pbx_builtin_setvar_helper(chan, "__SIPREFERREDBYHDR", S_OR(uri, NULL));
799 } else {
800 pbx_builtin_setvar_helper(chan, "SIPREFERREDBYHDR", NULL);
801 }
802
803 if (refer->replaces) {
804 char replaces[512];
805 char *replaces_val = NULL;
806 int len;
807
808 len = pjsip_hdr_print_on(refer->replaces, replaces, sizeof(replaces) - 1);
809 if (len != -1) {
810 /* pjsip_hdr_print_on does not NULL terminate the buffer */
811 replaces[len] = '\0';
812 replaces_val = replaces + sizeof("Replaces:");
813 }
814 pbx_builtin_setvar_helper(chan, "__SIPREPLACESHDR", replaces_val);
815 } else {
816 pbx_builtin_setvar_helper(chan, "SIPREPLACESHDR", NULL);
817 }
818
819 if (refer->refer_to) {
820 char refer_to[PJSIP_MAX_URL_SIZE];
821
822 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->refer_to, refer_to, sizeof(refer_to));
823 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", S_OR(refer_to, NULL));
824 } else {
825 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", NULL);
826 }
827}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#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:2922
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
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
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
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.
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
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:1023
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:1077
#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 1086 of file res_pjsip_refer.c.

1087{
1088 pjsip_tx_data *tdata;
1089 RAII_VAR(struct ast_sip_endpoint *, endpt, NULL, ao2_cleanup);
1091 int refer_success;
1092 int res = 0;
1093
1094 if (!event) {
1095 return;
1096 }
1097
1098 refer_data = pjsip_evsub_get_mod_data(sub, refer_out_of_dialog_module.id);
1099 if (!refer_data || !refer_data->dlg) {
1100 return;
1101 }
1102
1104
1105 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
1106 /* Check if subscription is suppressed and terminate and send completion code, if so. */
1107 pjsip_rx_data *rdata;
1108 pjsip_generic_string_hdr *refer_sub;
1109 const pj_str_t REFER_SUB = { "Refer-Sub", 9 };
1110
1111 ast_debug(3, "Refer accepted by %s\n", endpt ? ast_sorcery_object_get_id(endpt) : "(unknown endpoint)");
1112
1113 /* Check if response message */
1114 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1115 rdata = event->body.tsx_state.src.rdata;
1116
1117 /* Find Refer-Sub header */
1118 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &REFER_SUB, NULL);
1119
1120 /* Check if subscription is suppressed. If it is, the far end will not terminate it,
1121 * and the subscription will remain active until it times out. Terminating it here
1122 * eliminates the unnecessary timeout.
1123 */
1124 if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
1125 /* Since no subscription is desired, assume that call has been referred successfully
1126 * and terminate subscription.
1127 */
1128 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1129 pjsip_evsub_terminate(sub, PJ_TRUE);
1130 res = -1;
1131 }
1132 }
1133 } else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
1134 pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
1135 /* Check for NOTIFY complete or error. */
1136 pjsip_msg *msg;
1137 pjsip_msg_body *body;
1138 pjsip_status_line status_line = { .code = 0 };
1139 pj_bool_t is_last;
1140 pj_status_t status;
1141
1142 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1143 pjsip_rx_data *rdata;
1144 pj_str_t refer_str;
1145 pj_cstr(&refer_str, "REFER");
1146
1147 rdata = event->body.tsx_state.src.rdata;
1148 msg = rdata->msg_info.msg;
1149
1150 if (msg->type == PJSIP_RESPONSE_MSG
1151 && (event->body.tsx_state.tsx->status_code == 401
1152 || event->body.tsx_state.tsx->status_code == 407)
1153 && pj_stristr(&refer_str, &event->body.tsx_state.tsx->method.name)
1154 && ++refer_data->authentication_challenge_count < MAX_RX_CHALLENGES
1155 && endpt) {
1156
1157 if (!ast_sip_create_request_with_auth(&endpt->outbound_auths,
1158 event->body.tsx_state.src.rdata, event->body.tsx_state.tsx->last_tx, &tdata)) {
1159 /* Send authed REFER */
1161 goto out;
1162 }
1163 }
1164
1165 if (msg->type == PJSIP_REQUEST_MSG) {
1166 if (!pjsip_method_cmp(&msg->line.req.method, pjsip_get_notify_method())) {
1167 body = msg->body;
1168 if (body && !pj_stricmp2(&body->content_type.type, "message")
1169 && !pj_stricmp2(&body->content_type.subtype, "sipfrag")) {
1170 pjsip_parse_status_line((char *)body->data, body->len, &status_line);
1171 }
1172 }
1173 } else {
1174 status_line.code = msg->line.status.code;
1175 status_line.reason = msg->line.status.reason;
1176 }
1177 } else {
1178 status_line.code = 500;
1179 status_line.reason = *pjsip_get_status_text(500);
1180 }
1181
1182 is_last = (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED);
1183 /* If the status code is >= 200, the subscription is finished. */
1184 if (status_line.code >= 200 || is_last) {
1185 res = -1;
1186
1187 refer_success = status_line.code >= 200 && status_line.code < 300;
1188
1189 /* If subscription not terminated and subscription is finished (status code >= 200)
1190 * terminate it */
1191 if (!is_last) {
1192 pjsip_tx_data *tdata;
1193
1194 status = pjsip_evsub_initiate(sub, pjsip_get_subscribe_method(), 0, &tdata);
1195 if (status == PJ_SUCCESS) {
1196 pjsip_evsub_send_request(sub, tdata);
1197 }
1198 }
1199 ast_debug(3, "Refer completed: %d %.*s (%s)\n",
1200 status_line.code,
1201 (int)status_line.reason.slen, status_line.reason.ptr,
1202 refer_success ? "Success" : "Failure");
1203 }
1204 }
1205
1206out:
1207 if (res) {
1209 }
1210}
jack_status_t status
Definition: app_jack.c:146
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:110
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
An entity with which Asterisk communicates.
Definition: res_pjsip.h:963
Definition: astman.c:222
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 868 of file res_pjsip_refer.c.

869{
870 char *uri_params;
871 const char *destination;
873
874 if (!rdata) {
875 return NULL;
876 }
877
878 /* typecast to suppress const warning */
879 rdata->refer = ast_refer_ref((struct ast_refer *) refer);
881
882 /* To starts with 'pjsip:' which needs to be removed. */
883 if (!(destination = strchr(destination, ':'))) {
884 goto failure;
885 }
886 ++destination;/* Now skip the ':' */
887
889 if (!rdata->destination) {
890 goto failure;
891 }
892
894 if (!rdata->from) {
895 goto failure;
896 }
897
899 if (!rdata->refer_to) {
900 goto failure;
901 }
903
904 /*
905 * Sometimes from URI can contain URI parameters, so remove them.
906 *
907 * sip:user;user-options@domain;uri-parameters
908 */
909 uri_params = strchr(rdata->from, '@');
910 if (uri_params && (uri_params = strchr(uri_params, ';'))) {
911 *uri_params = '\0';
912 }
913 return rdata;
914
915failure:
916 ao2_cleanup(rdata);
917 return NULL;
918}
const char * ast_refer_get_to(const struct ast_refer *refer)
Retrieve the destination of this refer.
Definition: refer.c:229
const char * ast_refer_get_from(const struct ast_refer *refer)
Retrieve the source of this refer.
Definition: refer.c:224
const char * ast_refer_get_refer_to(const struct ast_refer *refer)
Get the "refer-to" value of a refer.
Definition: refer.c:219
struct ast_refer * ast_refer_ref(struct ast_refer *refer)
Bump a refer's ref count.
Definition: refer.c:146
int ast_refer_get_to_self(const struct ast_refer *refer)
Retrieve the "to_self" value of this refer.
Definition: refer.c:234
static void refer_data_destroy(void *obj)
A refer.
Definition: refer.c:57
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 857 of file res_pjsip_refer.c.

858{
859 struct refer_data *rdata = obj;
860
861 ast_free(rdata->destination);
862 ast_free(rdata->from);
863 ast_free(rdata->refer_to);
864
865 ast_refer_destroy(rdata->refer);
866}
struct ast_refer * ast_refer_destroy(struct ast_refer *refer)
Destroy an ast_refer.
Definition: refer.c:152

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

1344{
1345 const pj_str_t str_replaces = { "Replaces", 8 };
1346 pj_str_t replaces_content;
1347 pjsip_replaces_hdr *replaces;
1348 int parsed_len;
1349 pjsip_dialog *dlg;
1350
1351 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1352
1353 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1354 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1355 pj_strlen(&replaces_content), &parsed_len))) {
1356 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1358 return 400;
1359 }
1360
1361 /* See if the dialog is local, or remote */
1362 if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
1363 RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
1364 struct refer_attended *attended;
1365
1366 pjsip_dlg_dec_lock(dlg);
1367
1368 if (!other_session) {
1369 ast_debug(3, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it\n",
1371 return 603;
1372 }
1373
1374 /* We defer actually doing the attended transfer to the other session so no deadlock can occur */
1375 if (!(attended = refer_attended_alloc(session, other_session, progress))) {
1376 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",
1378 return 500;
1379 }
1380
1382 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not defer termination, rejecting\n",
1384 ao2_cleanup(attended);
1385 return 500;
1386 }
1387
1388 /* Push it to the other session, which will have both channels with minimal locking */
1389 if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {
1392 ao2_cleanup(attended);
1393 return 500;
1394 }
1395
1396 ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
1397 ast_channel_name(session->channel));
1398
1399 return 200;
1400 } else {
1401 const char *context;
1402 struct refer_blind refer = { 0, };
1403 int response;
1404
1406
1407 if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
1408 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",
1410 return 404;
1411 }
1412
1413 refer.context = context;
1414 refer.progress = progress;
1415 refer.rdata = rdata;
1416 refer.replaces = replaces;
1417 refer.refer_to = target_uri;
1418 refer.attended = 1;
1419
1421 ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting\n",
1422 ast_channel_name(session->channel),
1424 return 500;
1425 }
1426
1428 "external_replaces", context, refer_blind_callback, &refer));
1429
1431 if (response != 200) {
1433 }
1434
1435 return response;
1436 }
1437}
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:4425
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:4175
#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.
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.

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

1441{
1442 const char *context;
1443 char exten[AST_MAX_EXTENSION];
1444 struct refer_blind refer = { 0, };
1445 int response;
1446
1447 /* If no explicit transfer context has been provided use their configured context */
1449
1450 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1451 ast_copy_pj_str(exten, &target->user, sizeof(exten));
1452
1453 /*
1454 * We may want to match in the dialplan without any user
1455 * options getting in the way.
1456 */
1458
1459 /* Uri without exten */
1460 if (ast_strlen_zero(exten)) {
1461 ast_copy_string(exten, "s", sizeof(exten));
1462 ast_debug(3, "Channel '%s' from endpoint '%s' attempted blind transfer to a target without extension. Target was set to 's@%s'\n",
1464 }
1465
1466 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
1467 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
1468 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context);
1469 return 404;
1470 }
1471
1472 refer.context = context;
1473 refer.progress = progress;
1474 refer.rdata = rdata;
1475 refer.refer_to = target;
1476 refer.attended = 0;
1477
1479 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer but could not defer termination, rejecting\n",
1480 ast_channel_name(session->channel),
1482 return 500;
1483 }
1484
1486 exten, context, refer_blind_callback, &refer));
1487
1489 if (response != 200) {
1491 }
1492
1493 return response;
1494}
#define AST_MAX_EXTENSION
Definition: channel.h:134
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3351
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 1522 of file res_pjsip_refer.c.

1523{
1524 pjsip_dialog *other_dlg = NULL;
1525 pjsip_tx_data *packet;
1526 int response = 0;
1527 RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup);
1528 struct invite_replaces invite;
1529
1530 /* If a Replaces header is present make sure it is valid */
1531 if (pjsip_replaces_verify_request(rdata, &other_dlg, PJ_TRUE, &packet) != PJ_SUCCESS) {
1532 response = packet->msg->line.status.code;
1533 ast_assert(response != 0);
1534 pjsip_tx_data_dec_ref(packet);
1535 goto inv_replace_failed;
1536 }
1537
1538 /* If no other dialog exists then this INVITE request does not have a Replaces header */
1539 if (!other_dlg) {
1540 return 0;
1541 }
1542
1543 other_session = ast_sip_dialog_get_session(other_dlg);
1544 pjsip_dlg_dec_lock(other_dlg);
1545
1546 /* Don't accept an in-dialog INVITE with Replaces as it does not make much sense */
1547 if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
1548 response = 488;
1549 goto inv_replace_failed;
1550 }
1551
1552 if (!other_session) {
1553 ast_debug(3, "INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist\n",
1555 response = 481;
1556 goto inv_replace_failed;
1557 }
1558
1559 invite.session = other_session;
1560
1561 if (ast_sip_push_task_wait_serializer(other_session->serializer, invite_replaces,
1562 &invite)) {
1563 response = 481;
1564 goto inv_replace_failed;
1565 }
1566
1567 ast_channel_lock(session->channel);
1569 ast_channel_unlock(session->channel);
1570 ast_raw_answer(session->channel);
1571
1572 ast_debug(3, "INVITE with Replaces being attempted. '%s' --> '%s'\n",
1573 ast_channel_name(session->channel), ast_channel_name(invite.channel));
1574
1575 /* Unhold the channel now, as later we are not having access to it anymore */
1576 ast_queue_unhold(session->channel);
1578
1579 if (!invite.bridge) {
1580 struct ast_channel *chan = session->channel;
1581
1582 /*
1583 * This will use a synchronous task but we aren't operating in
1584 * the serializer at this point in time, so it won't deadlock.
1585 */
1586 if (!ast_channel_move(invite.channel, chan)) {
1587 /*
1588 * We can't directly use session->channel because ast_channel_move()
1589 * does a masquerade which changes session->channel to a different
1590 * channel. To ensure we work on the right channel we store a
1591 * pointer locally before we begin so it remains valid.
1592 */
1593 ast_hangup(chan);
1594 } else {
1595 response = AST_CAUSE_FAILURE;
1596 }
1597 } else {
1598 if (ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL,
1600 response = AST_CAUSE_FAILURE;
1601 }
1602 }
1603
1604 ast_channel_unref(invite.channel);
1605 ao2_cleanup(invite.bridge);
1606
1607 if (!response) {
1608 /*
1609 * On success we cannot use session->channel in the debug message.
1610 * This thread either no longer has a ref to session->channel or
1611 * session->channel is no longer the original channel.
1612 */
1613 ast_debug(3, "INVITE with Replaces successfully completed.\n");
1614 } else {
1615 ast_debug(3, "INVITE with Replaces failed on channel '%s', hanging up with cause '%d'\n",
1616 ast_channel_name(session->channel), response);
1617 ast_channel_lock(session->channel);
1618 ast_channel_hangupcause_set(session->channel, response);
1619 ast_channel_unlock(session->channel);
1620 ast_hangup(session->channel);
1621 }
1622
1623 return 1;
1624
1625inv_replace_failed:
1626 if (session->inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
1627 ast_debug(3, "INVITE with Replaces failed on channel '%s', sending response of '%d'\n",
1628 ast_channel_name(session->channel), response);
1629 session->defer_terminate = 1;
1630 ast_hangup(session->channel);
1631
1632 if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS
1633 && packet) {
1635 }
1636 } else {
1637 ast_debug(3, "INVITE with Replaces in-dialog on channel '%s', hanging up\n",
1638 ast_channel_name(session->channel));
1639 ast_queue_hangup(session->channel);
1640 }
1641
1642 return 1;
1643}
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:1878
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition: bridge.h:590
#define AST_CAUSE_FAILURE
Definition: causes.h:150
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1150
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:1139
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:10666
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1216
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
int ast_raw_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2690
@ AST_STATE_RING
Definition: channelstate.h:40
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7386
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 1645 of file res_pjsip_refer.c.

1646{
1647 pjsip_generic_string_hdr *refer_to;
1648 char *uri;
1649 size_t uri_size;
1650 pjsip_uri *target;
1651 pjsip_sip_uri *target_uri;
1653 pjsip_param *replaces;
1654 int response;
1655
1656 static const pj_str_t str_refer_to = { "Refer-To", 8 };
1657 static const pj_str_t str_refer_to_s = { "r", 1 };
1658 static const pj_str_t str_replaces = { "Replaces", 8 };
1659
1660 if (!session->channel) {
1661 /* No channel to refer. Likely because the call was just hung up. */
1662 pjsip_dlg_respond(session->inv_session->dlg, rdata, 404, NULL, NULL, NULL);
1663 ast_debug(3, "Received a REFER on a session with no channel from endpoint '%s'.\n",
1665 return 0;
1666 }
1667
1668 if (!session->endpoint->allowtransfer) {
1669 pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
1670 ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
1672 return 0;
1673 }
1674
1675 /* A Refer-To header is required */
1676 refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL);
1677 if (!refer_to) {
1678 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1679 ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
1681 return 0;
1682 }
1683
1684 /* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri
1685 * as pjsip_parse_uri require a NULL terminated uri
1686 */
1687
1688 uri_size = pj_strlen(&refer_to->hvalue) + 1;
1689 uri = ast_alloca(uri_size);
1690 ast_copy_pj_str(uri, &refer_to->hvalue, uri_size);
1691
1692 target = pjsip_parse_uri(rdata->tp_info.pool, uri, uri_size - 1, 0);
1693
1694 if (!target
1695 || (!PJSIP_URI_SCHEME_IS_SIP(target)
1696 && !PJSIP_URI_SCHEME_IS_SIPS(target))) {
1697
1698 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1699 ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n",
1700 uri, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
1701 return 0;
1702 }
1703 target_uri = pjsip_uri_get_uri(target);
1704
1705 /* Set up REFER progress subscription if requested/possible */
1706 if (refer_progress_alloc(session, rdata, &progress)) {
1707 pjsip_dlg_respond(session->inv_session->dlg, rdata, 500, NULL, NULL, NULL);
1708 ast_debug(3, "Could not set up subscription for REFER on channel '%s' from endpoint '%s'\n",
1710 return 0;
1711 }
1712
1713 /* Determine if this is an attended or blind transfer */
1714 if ((replaces = pjsip_param_find(&target_uri->header_param, &str_replaces)) ||
1715 (replaces = pjsip_param_find(&target_uri->other_param, &str_replaces))) {
1716 response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
1717 } else {
1718 response = refer_incoming_blind_request(session, rdata, target_uri, progress);
1719 }
1720
1721 if (!progress) {
1722 /* The transferer has requested no subscription, so send a final response immediately */
1723 pjsip_tx_data *tdata;
1724 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
1725 const pj_str_t str_false = { "false", 5 };
1726 pjsip_hdr *hdr;
1727
1728 ast_debug(3, "Progress monitoring not requested for REFER on channel '%s' from endpoint '%s', sending immediate response of '%d'\n",
1729 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), response);
1730
1731 if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, response, NULL, &tdata) != PJ_SUCCESS) {
1732 pjsip_dlg_respond(session->inv_session->dlg, rdata, response, NULL, NULL, NULL);
1733 return 0;
1734 }
1735
1736 hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
1737 pjsip_msg_add_hdr(tdata->msg, hdr);
1738
1739 pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
1740 } else if (response != 200) {
1741 /* Since this failed we can send a final NOTIFY now and terminate the subscription */
1742 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
1743
1744 if (notification) {
1745 /* The refer_progress_notify function will call ao2_cleanup on this for us */
1746 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
1747 ao2_cleanup(notification);
1748 }
1749 }
1750 }
1751
1752 return 0;
1753}
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.
REFER Progress structure.

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

1756{
1757 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
1759 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_invite_method)) {
1761 } else {
1762 return 0;
1763 }
1764}
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 1015 of file res_pjsip_refer.c.

1015 {
1016 RAII_VAR(struct ast_str *, refer_to_str, ast_str_create(PJSIP_MAX_URL_SIZE), ast_free_ptr);
1017 const pj_str_t REFER_TO = { "Refer-To", 8 };
1018 pjsip_generic_string_hdr *refer_to_hdr;
1019 pjsip_dialog *dlg;
1020 struct refer_data *refer_data;
1021 pjsip_uri *parsed_uri;
1022 pjsip_sip_uri *refer_to_uri;
1023
1024 /*
1025 * If this is a request in response to a 401/407 Unauthorized challenge, the
1026 * Refer-To URI has been rewritten already, so don't attempt to re-write it again.
1027 * Checking for presence of the Authorization header is not an ideal solution. We do this because
1028 * there exists some race condition where this dialog is not the same as the one used
1029 * to send the original request in which case we don't have the correct refer_data.
1030 */
1031 if (!refer_to_str
1032 || pjsip_msg_find_hdr(tdata->msg, PJSIP_H_AUTHORIZATION, NULL)
1033 || !(dlg = pjsip_tdata_get_dlg(tdata))
1034 || !(refer_data = pjsip_dlg_get_mod_data(dlg, refer_out_of_dialog_module.id))
1035 || !refer_data->to_self
1036 || !(parsed_uri = get_refer_to_uri(tdata))) {
1037 goto out;
1038 }
1039 refer_to_uri = pjsip_uri_get_uri(parsed_uri);
1040 ast_sip_rewrite_uri_to_local(refer_to_uri, tdata);
1041
1042 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, parsed_uri, ast_str_buffer(refer_to_str), ast_str_size(refer_to_str));
1043 refer_to_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL);
1044 pj_strdup2(tdata->pool, &refer_to_hdr->hvalue, ast_str_buffer(refer_to_str));
1045
1046out:
1047 return PJ_SUCCESS;
1048}
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 1067 of file res_pjsip_refer.c.

1067 {
1068 struct refer_out_of_dialog *data = obj;
1069
1070 if (data->dlg) {
1071 /* ast_sip_push_task_wait_servant should not be called in a destructor,
1072 * however in this case it seems to be fine.
1073 */
1075 }
1076}
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)
pjsip_dialog * dlg

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

1800{
1801 if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method)
1802 || !session->channel
1803 || session->inv_session->state != PJSIP_INV_STATE_NULL) {
1804 return;
1805 }
1806
1807 ast_channel_lock(session->channel);
1808 add_header_from_channel_var(session->channel, "SIPREPLACESHDR", "Replaces", tdata);
1809 add_header_from_channel_var(session->channel, "SIPREFERREDBYHDR", "Referred-By", tdata);
1810 ast_channel_unlock(session->channel);
1811}
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_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 387 of file res_pjsip_refer.c.

388{
389 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
390 pjsip_generic_string_hdr *refer_sub = NULL;
391 const pj_str_t str_true = { "true", 4 };
392 pjsip_hdr hdr_list;
393 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
394
395 *progress = NULL;
396
397 /* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */
398 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
399 if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4))) {
400 return 0;
401 }
402
403 if (!(*progress = ao2_alloc(sizeof(struct refer_progress), refer_progress_destroy))) {
404 return -1;
405 }
406
407 ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
409
410 (*progress)->refer_blind_progress = session->endpoint->refer_blind_progress;
411
412 (*progress)->framehook = -1;
413
414 /* Create name with seq number appended. */
415 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/refer/%s",
417
418 if (!((*progress)->serializer = ast_sip_create_serializer(tps_name))) {
419 goto error;
420 }
421
422 /* Create the implicit subscription for monitoring of this transfer */
423 if (pjsip_xfer_create_uas(session->inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
424 goto error;
425 }
426
427 /* To prevent a potential deadlock we need the dialog so we can lock/unlock */
428 (*progress)->dlg = session->inv_session->dlg;
429 /* We also need to make sure it stays around until we're done with it */
430 pjsip_dlg_inc_session((*progress)->dlg, &refer_progress_module);
431
432
433 /* Associate the REFER progress structure with the subscription */
434 ao2_ref(*progress, +1);
435 pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
436
437 pj_list_init(&hdr_list);
438 if (refer_sub) {
439 pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->inv_session->dlg->pool, &str_refer_sub, &str_true);
440
441 pj_list_push_back(&hdr_list, hdr);
442 }
443
444 /* Accept the REFER request */
445 ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress);
446 pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
447
448 return 0;
449
450error:
452 *progress = NULL;
453 return -1;
454}
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
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 186 of file res_pjsip_refer.c.

188{
189 struct refer_progress *progress = data;
190 struct ast_bridge_blob *enter_blob;
191 struct refer_progress_notification *notification;
192 struct ast_channel *chan;
193
195 ao2_ref(progress, -1);
196 return;
197 }
198
200 /* Don't care */
201 return;
202 }
203
204 enter_blob = stasis_message_data(message);
205 if (strcmp(enter_blob->channel->base->uniqueid, progress->transferee)) {
206 /* Don't care */
207 return;
208 }
209
210 if (!progress->transfer_data->completed) {
211 /* We can't act on this message because the transfer_channel_data doesn't show that
212 * the transfer is ready to progress */
213 return;
214 }
215
216 /* OMG the transferee is joining a bridge. His call got answered! */
217 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
218 if (notification) {
219 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
220 ao2_cleanup(notification);
221 }
222 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
223 }
224
225 chan = ast_channel_get_by_name(progress->transferee);
226 if (!chan) {
227 /* The channel is already gone */
228 return;
229 }
230
231 ast_channel_lock(chan);
232 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as it has joined a bridge\n",
233 ast_channel_name(chan));
234 ast_framehook_detach(chan, progress->framehook);
235 ast_channel_unlock(chan);
236
237 ast_channel_unref(chan);
238}
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
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:1174
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:971
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 354 of file res_pjsip_refer.c.

355{
356 struct refer_progress *progress = obj;
357
358 if (progress->bridge_sub) {
359 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
360 }
361
362 if (progress->dlg) {
363 /*
364 * Although the dlg session count was incremented in a pjsip servant
365 * thread, there's no guarantee that the last thread to unref this progress
366 * object was one. Before we decrement, we need to make sure that this
367 * is either a servant thread or that we push the decrement to a
368 * serializer that is one.
369 *
370 * Because pjsip_dlg_dec_session requires the dialog lock, we don't want
371 * to wait on the task to complete if we had to push it to a serializer.
372 */
374 pjsip_dlg_dec_session(progress->dlg, &refer_progress_module);
375 } else {
377 }
378 }
379
380 ao2_cleanup(progress->transfer_data);
381
382 ast_free(progress->transferee);
384}
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 241 of file res_pjsip_refer.c.

242{
243 struct refer_progress *progress = data;
244 struct refer_progress_notification *notification = NULL;
245
246 /* We only care about frames *to* the channel */
247 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
248 return f;
249 }
250
251 /* If the completed flag hasn't been raised, skip this pass. */
252 if (!progress->transfer_data->completed) {
253 return f;
254 }
255
256 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
257 if (f->frametype == AST_FRAME_VOICE && !progress->subclass) {
258 /* Media is passing without progress, this means the call has been answered */
259 progress->subclass = AST_CONTROL_ANSWER;
260 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
261 } else if (f->frametype == AST_FRAME_CONTROL) {
262 /* Based on the control frame being written we can send a NOTIFY advising of the progress */
264 /* Don't set progress->subclass; an ANSWER can still follow */
265 notification = refer_progress_notification_alloc(progress, 180, PJSIP_EVSUB_STATE_ACTIVE);
266 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
267 progress->subclass = f->subclass.integer;
268 notification = refer_progress_notification_alloc(progress, 486, PJSIP_EVSUB_STATE_TERMINATED);
269 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
270 progress->subclass = f->subclass.integer;
271 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
272 } else if (f->subclass.integer == AST_CONTROL_PROGRESS) {
273 /* Don't set progress->subclass; an ANSWER can still follow */
274 notification = refer_progress_notification_alloc(progress, 183, PJSIP_EVSUB_STATE_ACTIVE);
275 } else if (f->subclass.integer == AST_CONTROL_PROCEEDING) {
276 /* Don't set progress->subclass; an ANSWER can still follow */
277 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
278 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
279 progress->subclass = f->subclass.integer;
280 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
281 }
282 }
283
284 /* If a notification is due to be sent push it to the thread pool */
285 if (notification) {
286 /* If the subscription is being terminated we don't need the frame hook any longer */
287 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
288 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
289 ast_channel_name(chan));
290 ast_framehook_detach(chan, progress->framehook);
291 }
292
293 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
294 ao2_cleanup(notification);
295 }
296 }
297
298 return f;
299}
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
@ AST_FRAME_VOICE
@ AST_FRAME_CONTROL
@ AST_CONTROL_RING
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_BUSY
@ AST_CONTROL_PROCEEDING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
struct ast_frame_subclass subclass
enum ast_frame_type frametype
pjsip_evsub_state state
Subscription state.

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

303{
304 struct refer_progress *progress = data;
305 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
306
307 if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
308 ao2_cleanup(notification);
309 }
310
311 if (progress->bridge_sub) {
312 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
313 }
314
316}

References ao2_cleanup, ast_sip_push_task(), refer_progress_notification_alloc(), refer_progress_notify(), and stasis_unsubscribe().

Referenced by refer_blind_callback().

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

101{
102 struct refer_progress_notification *notification = ao2_alloc(sizeof(*notification), refer_progress_notification_destroy);
103
104 if (!notification) {
105 return NULL;
106 }
107
108 ao2_ref(progress, +1);
109 notification->progress = progress;
110 notification->response = response;
111 notification->state = state;
112
113 return notification;
114}
enum cc_state state
Definition: ccss.c:393
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_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 91 of file res_pjsip_refer.c.

92{
93 struct refer_progress_notification *notification = obj;
94
95 ao2_cleanup(notification->progress);
96}

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

146{
147 RAII_VAR(struct refer_progress_notification *, notification, data, ao2_cleanup);
148 pjsip_evsub *sub;
149 pjsip_tx_data *tdata;
150
151 pjsip_dlg_inc_lock(notification->progress->dlg);
152
153 /* If the subscription has already been terminated we can't send a notification */
154 if (!(sub = notification->progress->sub)) {
155 ast_debug(3, "Not sending NOTIFY of response '%d' and state '%u' on progress monitor '%p' as subscription has been terminated\n",
156 notification->response, notification->state, notification->progress);
157 pjsip_dlg_dec_lock(notification->progress->dlg);
158 return 0;
159 }
160
161 /* Send a deferred initial 100 Trying SIP frag NOTIFY if we haven't already. */
162 if (!notification->progress->sent_100) {
163 notification->progress->sent_100 = 1;
164 if (notification->response != 100) {
165 ast_debug(3, "Sending initial 100 Trying NOTIFY for progress monitor '%p'\n",
166 notification->progress);
167 if (pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) {
168 pjsip_xfer_send_request(sub, tdata);
169 }
170 }
171 }
172
173 ast_debug(3, "Sending NOTIFY with response '%d' and state '%u' on subscription '%p' and progress monitor '%p'\n",
174 notification->response, notification->state, sub, notification->progress);
175
176 /* Actually send the notification */
177 if (pjsip_xfer_notify(sub, notification->state, notification->response, NULL, &tdata) == PJ_SUCCESS) {
178 pjsip_xfer_send_request(sub, tdata);
179 }
180
181 pjsip_dlg_dec_lock(notification->progress->dlg);
182
183 return 0;
184}

References ao2_cleanup, ast_debug, NULL, RAII_VAR, and sub.

Referenced by 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 328 of file res_pjsip_refer.c.

329{
330 struct refer_progress *progress = pjsip_evsub_get_mod_data(sub, refer_progress_module.id);
331
332 /*
333 * If being destroyed, remove the progress object from the subscription
334 * and release the reference it had.
335 */
336 if (progress && (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)) {
337 pjsip_evsub_set_mod_data(progress->sub, refer_progress_module.id, NULL);
338 progress->sub = NULL;
340 }
341}

References ao2_cleanup, NULL, refer_progress_module, and sub.

◆ refer_send()

static int refer_send ( void *  data)
static

Definition at line 1220 of file res_pjsip_refer.c.

1221{
1222 struct refer_data *rdata = data; /* The caller holds a reference */
1223 pjsip_tx_data *tdata;
1224 pjsip_evsub *sub;
1225 pj_str_t tmp;
1226 char refer_to_str[PJSIP_MAX_URL_SIZE];
1227 char disp_name_escaped[128];
1228 struct refer_out_of_dialog *refer;
1229 struct pjsip_evsub_user xfer_cb;
1230 RAII_VAR(char *, uri, NULL, ast_free);
1231 RAII_VAR(char *, tmp_str, NULL, ast_free);
1232 RAII_VAR(char *, display_name, NULL, ast_free);
1233 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1234 RAII_VAR(struct ast_sip_endpoint *, refer_to_endpoint, NULL, ao2_cleanup);
1235
1236 endpoint = ast_sip_get_endpoint(rdata->destination, 1, &uri);
1237 if (!endpoint) {
1239 "PJSIP REFER - Could not find endpoint '%s' and no default outbound endpoint configured\n",
1240 rdata->destination);
1241 return -1;
1242 }
1243 ast_debug(3, "Request URI: %s\n", uri);
1244
1245 refer_to_endpoint = ast_sip_get_endpoint(rdata->refer_to, 0, &tmp_str);
1246 if (!tmp_str) {
1247 ast_log(LOG_WARNING, "PJSIP REFER - Refer to not a valid resource identifier or SIP URI\n");
1248 return -1;
1249 }
1250 if (!(refer = ao2_alloc(sizeof(struct refer_out_of_dialog), refer_out_of_dialog_destroy))) {
1251 ast_log(LOG_ERROR, "PJSIP REFER - Could not allocate resources.\n");
1252 return -1;
1253 }
1254 /* The dialog will be terminated in the subscription event callback
1255 * when the subscription has terminated. */
1257 refer->dlg = ast_sip_create_dialog_uac(endpoint, uri, NULL);
1258 if (!refer->dlg) {
1259 ast_log(LOG_WARNING, "PJSIP REFER - Could not create dialog\n");
1260 ao2_cleanup(refer);
1261 return -1;
1262 }
1263 ast_sip_dialog_set_endpoint(refer->dlg, endpoint);
1264
1265 pj_bzero(&xfer_cb, sizeof(xfer_cb));
1266 xfer_cb.on_evsub_state = &refer_client_on_evsub_state;
1267 if (pjsip_xfer_create_uac(refer->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
1268 ast_log(LOG_WARNING, "PJSIP REFER - Could not create uac\n");
1269 ao2_cleanup(refer);
1270 return -1;
1271 }
1272
1273 display_name = ast_refer_get_var_and_unlink(rdata->refer, "display_name");
1274 if (display_name) {
1275 ast_escape_quoted(display_name, disp_name_escaped, sizeof(disp_name_escaped));
1276 snprintf(refer_to_str, sizeof(refer_to_str), "\"%s\" <%s>", disp_name_escaped, tmp_str);
1277 } else {
1278 snprintf(refer_to_str, sizeof(refer_to_str), "%s", tmp_str);
1279 }
1280
1281 /* refer_out_of_dialog_module requires a reference to dlg
1282 * which will be released in refer_client_on_evsub_state()
1283 * when the implicit REFER subscription terminates */
1284 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, refer);
1285 if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, refer_to_str), &tdata) != PJ_SUCCESS) {
1286 ast_log(LOG_WARNING, "PJSIP REFER - Could not create request\n");
1287 goto failure;
1288 }
1289
1290 if (refer_to_endpoint && rdata->to_self) {
1291 pjsip_dlg_add_usage(refer->dlg, &refer_out_of_dialog_module, rdata);
1292 }
1293
1294 ast_sip_update_to_uri(tdata, uri);
1295 ast_sip_update_from(tdata, rdata->from);
1296
1297 /*
1298 * This copies any headers found in the refer's variables to
1299 * tdata.
1300 */
1301 vars_to_headers(rdata->refer, tdata);
1302 ast_debug(1, "Sending REFER to '%s' (via endpoint %s) from '%s'\n",
1303 rdata->destination, ast_sorcery_object_get_id(endpoint), rdata->from);
1304
1305 if (pjsip_xfer_send_request(sub, tdata) == PJ_SUCCESS) {
1306 return 0;
1307 }
1308
1309failure:
1310 ao2_cleanup(refer);
1311 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1312 pjsip_evsub_terminate(sub, PJ_FALSE);
1313 return -1;
1314}
static int tmp()
Definition: bt_open.c:389
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:267
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, tmp(), 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 1050 of file res_pjsip_refer.c.

1051{
1052 struct refer_out_of_dialog *data = obj;
1053
1054 /* This is why we keep the dialog on the subscription. When the subscription
1055 * is destroyed, there is no guarantee that the underlying dialog is ready
1056 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1057 * either. The dialog could be destroyed before our subscription is. We fix
1058 * this problem by keeping a reference to the dialog until it is time to
1059 * destroy the subscription.
1060 */
1061 pjsip_dlg_dec_session(data->dlg, &refer_out_of_dialog_module);
1062 data->dlg = NULL;
1063
1064 return 0;
1065}

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

508{
509 struct ast_sip_session *session = data;
510
512 ao2_ref(session, -1);
513 return 0;
514}

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

1317{
1318 struct refer_data *rdata;
1319 int res;
1320
1322 ast_log(LOG_ERROR, "SIP REFER - a 'To' URI must be specified\n");
1323 return -1;
1324 }
1325
1326 rdata = refer_data_create(refer);
1327 if (!rdata) {
1328 return -1;
1329 }
1330
1332 ao2_ref(rdata, -1);
1333
1334 return res;
1335}
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.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1849 of file res_pjsip_refer.c.

1850{
1855
1856 return 0;
1857}
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 967 of file res_pjsip_refer.c.

968{
969 const char *name;
970 const char *value;
972
973 for (iter = ast_refer_var_iterator_init(refer);
978 }
979 }
981
982 return PJSIP_SC_OK;
983}
void ast_refer_var_unref_current(struct ast_refer_var_iterator *iter)
Unref a refer var from inside an iterator loop.
Definition: refer.c:370
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:349
struct ast_refer_var_iterator * ast_refer_var_iterator_init(const struct ast_refer *refer)
Create a new refer variable iterator.
Definition: refer.c:335
void ast_refer_var_iterator_destroy(struct ast_refer_var_iterator *iter)
Destroy a refer variable iterator.
Definition: refer.c:376
static int is_refer_var_blocked(const char *name)
struct ao2_iterator iter
Definition: refer.c:331
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 535 of file res_pjsip_refer.c.

536{
537 int response;
538
539 response = 503;
540 switch (xfer_code) {
542 response = 400;
543 break;
545 response = 403;
546 break;
548 response = 500;
549 break;
551 response = 200;
552 break;
553 }
554 return response;
555}
@ AST_BRIDGE_TRANSFER_NOT_PERMITTED
Definition: bridge.h:1102
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1100
@ AST_BRIDGE_TRANSFER_INVALID
Definition: bridge.h:1104
@ AST_BRIDGE_TRANSFER_FAIL
Definition: bridge.h:1106

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

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1865 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 991 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 344 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 85 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:3186
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 1813 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 1337 of file res_pjsip_refer.c.

Referenced by ast_refer_send(), and load_module().