32 #include "asterisk/res_pjsip.h"
33 #include "asterisk/res_pjsip_session.h"
39 #include "asterisk/stasis_bridges.h"
40 #include "asterisk/stasis_channels.h"
46 static pj_status_t refer_on_tx_request(pjsip_tx_data *tdata);
85 static pjsip_module refer_progress_module = {
86 .name = {
"REFER Progress", 14 },
91 static void refer_progress_notification_destroy(
void *obj)
100 pjsip_evsub_state
state)
145 static int refer_progress_notify(
void *data)
149 pjsip_tx_data *tdata;
155 ast_debug(3,
"Not sending NOTIFY of response '%d' and state '%u' on progress monitor '%p' as subscription has been terminated\n",
164 if (notification->
response != 100) {
165 ast_debug(3,
"Sending initial 100 Trying NOTIFY for progress monitor '%p'\n",
167 if (pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) {
168 pjsip_xfer_send_request(sub, tdata);
173 ast_debug(3,
"Sending NOTIFY with response '%d' and state '%u' on subscription '%p' and progress monitor '%p'\n",
177 if (pjsip_xfer_notify(sub, notification->
state, notification->
response, NULL, &tdata) == PJ_SUCCESS) {
178 pjsip_xfer_send_request(sub, tdata);
217 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
220 ao2_cleanup(notification);
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));
235 ast_channel_unlock(chan);
260 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
265 notification = refer_progress_notification_alloc(progress, 180, PJSIP_EVSUB_STATE_ACTIVE);
268 notification = refer_progress_notification_alloc(progress, 486, PJSIP_EVSUB_STATE_TERMINATED);
271 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
274 notification = refer_progress_notification_alloc(progress, 183, PJSIP_EVSUB_STATE_ACTIVE);
277 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
280 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
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));
294 ao2_cleanup(notification);
302 static void refer_progress_framehook_destroy(
void *data)
308 ao2_cleanup(notification);
315 ao2_cleanup(progress);
328 static void refer_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
330 struct refer_progress *progress = pjsip_evsub_get_mod_data(sub, refer_progress_module.id);
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;
339 ao2_cleanup(progress);
344 static pjsip_evsub_user refer_progress_evsub_cb = {
345 .on_evsub_state = refer_progress_on_evsub_state,
348 static int dlg_releaser_task(
void *data) {
349 pjsip_dlg_dec_session((pjsip_dialog *)data, &refer_progress_module);
354 static void refer_progress_destroy(
void *obj)
374 pjsip_dlg_dec_session(progress->
dlg, &refer_progress_module);
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 };
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))) {
403 if (!(*progress = ao2_alloc(
sizeof(
struct refer_progress), refer_progress_destroy))) {
407 ast_debug(3,
"Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
412 (*progress)->framehook = -1;
423 if (pjsip_xfer_create_uas(session->
inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
430 pjsip_dlg_inc_session((*progress)->dlg, &refer_progress_module);
435 pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
437 pj_list_init(&hdr_list);
439 pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->
inv_session->dlg->pool, &str_refer_sub, &str_true);
441 pj_list_push_back(&hdr_list, hdr);
445 ast_debug(3,
"Accepting REFER request for progress monitor '%p'\n", *progress);
446 pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
451 ao2_cleanup(*progress);
469 static void refer_attended_destroy(
void *obj)
486 attended = ao2_alloc_options(
sizeof(*attended), refer_attended_destroy,
496 ao2_ref(transferer_second, +1);
507 static int session_end_if_deferred_task(
void *data)
511 ast_sip_session_end_if_deferred(session);
516 static int defer_termination_cancel_task(
void *data)
520 ast_sip_session_end_if_deferred(session);
521 ast_sip_session_defer_termination_cancel(session);
558 static int refer_attended_task(
void *data)
562 int (*task_cb)(
void *data);
565 ast_debug(3,
"Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
573 ast_debug(3,
"Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
578 ast_debug(3,
"Received REFER request on channel '%s' but other channel has gone.\n",
586 notification = refer_progress_notification_alloc(attended->
progress, response,
587 PJSIP_EVSUB_STATE_TERMINATED);
590 ao2_cleanup(notification);
595 if (response == 200) {
596 task_cb = session_end_if_deferred_task;
598 task_cb = defer_termination_cancel_task;
606 ast_sip_session_end_if_deferred(attended->
transferer);
626 unsigned int attended:1;
633 struct refer_blind *refer = user_data_wrapper->data;
634 pjsip_generic_string_hdr *referred_by;
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;
645 PJSIP_EVSUB_STATE_TERMINATED);
649 ao2_cleanup(notification);
655 .
version = AST_FRAMEHOOK_INTERFACE_VERSION,
656 .event_cb = refer_progress_framehook,
657 .destroy_cb = refer_progress_framehook_destroy,
659 .disable_inheritance = 1,
665 PJSIP_EVSUB_STATE_TERMINATED);
667 ast_log(LOG_WARNING,
"Could not copy channel name '%s' during transfer - assuming success\n",
668 ast_channel_name(chan));
672 ao2_cleanup(notification);
678 ao2_ref(user_data_wrapper, +1);
685 ast_channel_lock(chan);
687 ast_channel_unlock(chan);
690 PJSIP_EVSUB_STATE_TERMINATED);
692 ast_log(LOG_WARNING,
"Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
693 ast_channel_name(chan));
697 ao2_cleanup(notification);
712 PJSIP_EVSUB_STATE_TERMINATED);
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));
719 ao2_cleanup(notification);
723 ast_channel_lock(chan);
725 ast_channel_unlock(chan);
737 ast_channel_lock(chan);
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;
748 const char *prefix = get_xfrdata;
751 if (!strcmp(prefix,
"*")) {
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;
759 char hdr_name[hdr_name_bytes];
763 ast_copy_pj_str(hdr_name, &hdr->name, hdr_name_bytes);
764 len = pjsip_hdr_print_on(hdr, buf,
sizeof(buf) - 1);
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));
773 value_str = strchr(buf,
':');
780 ast_str_set(&pbxvar, -1,
"~HASH~TRANSFER_DATA~%.*s~", hdr_name_strlen, hdr_name);
782 ast_debug(5,
"On channel '%s' set TRANSFER_DATA variable '%s' to value '%s' \n", ast_channel_name(chan), hdr_name, value_str);
787 ast_log(LOG_ERROR,
"Channel '%s' failed to allocate buffer for TRANSFER_DATA variable\n", ast_channel_name(chan));
791 referred_by = pjsip_msg_find_hdr_by_names(refer->
rdata->msg_info.msg,
792 &str_referred_by, &str_referred_by_s, NULL);
794 size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
797 ast_copy_pj_str(uri, &referred_by->hvalue, uri_size);
805 char *replaces_val = NULL;
808 len = pjsip_hdr_print_on(refer->
replaces, replaces,
sizeof(replaces) - 1);
811 replaces[len] =
'\0';
812 replaces_val = replaces +
sizeof(
"Replaces:");
820 char refer_to[PJSIP_MAX_URL_SIZE];
822 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->
refer_to, refer_to,
sizeof(refer_to));
837 #define DETERMINE_TRANSFER_CONTEXT(context, session) \
839 ast_channel_lock((session)->channel); \
840 context = pbx_builtin_getvar_helper((session)->channel, "TRANSFER_CONTEXT"); \
841 if (ast_strlen_zero(context)) { \
842 context = (session)->endpoint->context; \
844 context = ast_strdupa(context); \
846 ast_channel_unlock((session)->channel); \
857 static void refer_data_destroy(
void *obj)
861 ast_free(rdata->destination);
862 ast_free(rdata->from);
863 ast_free(rdata->refer_to);
871 const char *destination;
883 if (!(destination = strchr(destination,
':'))) {
889 if (!rdata->destination) {
899 if (!rdata->refer_to) {
909 uri_params = strchr(rdata->from,
'@');
910 if (uri_params && (uri_params = strchr(uri_params,
';'))) {
932 static int is_refer_var_blocked(
const char *name)
937 static const char *hdr[] = {
951 for (i = 0; i < ARRAY_LEN(hdr); ++i) {
952 if (!strcasecmp(name, hdr[i])) {
967 static enum pjsip_status_code vars_to_headers(
const struct ast_refer *refer, pjsip_tx_data *tdata)
976 if (!is_refer_var_blocked(name)) {
977 ast_sip_add_header(tdata, name, value);
987 int authentication_challenge_count;
991 static pjsip_module refer_out_of_dialog_module = {
992 .name = {
"REFER Out-of-dialog Module", 26 },
994 .on_tx_request = refer_on_tx_request,
996 .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 4,
1000 static pjsip_uri *get_refer_to_uri(pjsip_tx_data *tdata)
1002 const pj_str_t REFER_TO = {
"Refer-To", 8 };
1003 pjsip_generic_string_hdr *refer_to;
1004 pjsip_uri *parsed_uri;
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))) {
1015 static pj_status_t refer_on_tx_request(pjsip_tx_data *tdata) {
1017 const pj_str_t REFER_TO = {
"Refer-To", 8 };
1018 pjsip_generic_string_hdr *refer_to_hdr;
1021 pjsip_uri *parsed_uri;
1022 pjsip_sip_uri *refer_to_uri;
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))) {
1039 refer_to_uri = pjsip_uri_get_uri(parsed_uri);
1040 ast_sip_rewrite_uri_to_local(refer_to_uri, tdata);
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));
1050 static int refer_unreference_dialog(
void *obj)
1061 pjsip_dlg_dec_session(data->dlg, &refer_out_of_dialog_module);
1067 static void refer_out_of_dialog_destroy(
void *obj) {
1086 static void refer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
1088 pjsip_tx_data *tdata;
1098 refer_data = pjsip_evsub_get_mod_data(sub, refer_out_of_dialog_module.id);
1099 if (!refer_data || !refer_data->dlg) {
1105 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
1107 pjsip_rx_data *rdata;
1108 pjsip_generic_string_hdr *refer_sub;
1109 const pj_str_t REFER_SUB = {
"Refer-Sub", 9 };
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;
1118 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &REFER_SUB, NULL);
1124 if (refer_sub && !pj_stricmp2(&refer_sub->hvalue,
"false")) {
1128 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1129 pjsip_evsub_terminate(sub, PJ_TRUE);
1133 }
else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
1134 pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
1137 pjsip_msg_body *body;
1138 pjsip_status_line status_line = { .code = 0 };
1142 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1143 pjsip_rx_data *rdata;
1145 pj_cstr(&refer_str,
"REFER");
1147 rdata =
event->body.tsx_state.src.rdata;
1148 msg = rdata->msg_info.msg;
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
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)) {
1160 ast_sip_send_request(tdata, refer_data->dlg, NULL, NULL, NULL);
1165 if (msg->type == PJSIP_REQUEST_MSG) {
1166 if (!pjsip_method_cmp(&msg->line.req.method, pjsip_get_notify_method())) {
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);
1174 status_line.code = msg->line.status.code;
1175 status_line.reason = msg->line.status.reason;
1178 status_line.code = 500;
1179 status_line.reason = *pjsip_get_status_text(500);
1182 is_last = (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED);
1184 if (status_line.code >= 200 || is_last) {
1187 refer_success = status_line.code >= 200 && status_line.code < 300;
1192 pjsip_tx_data *tdata;
1194 status = pjsip_evsub_initiate(sub, pjsip_get_subscribe_method(), 0, &tdata);
1195 if (status == PJ_SUCCESS) {
1196 pjsip_evsub_send_request(sub, tdata);
1199 ast_debug(3,
"Refer completed: %d %.*s (%s)\n",
1201 (
int)status_line.reason.slen, status_line.reason.ptr,
1202 refer_success ?
"Success" :
"Failure");
1208 ao2_cleanup(refer_data);
1220 static int refer_send(
void *data)
1222 struct refer_data *rdata = data;
1223 pjsip_tx_data *tdata;
1226 char refer_to_str[PJSIP_MAX_URL_SIZE];
1227 char disp_name_escaped[128];
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);
1236 endpoint = ast_sip_get_endpoint(rdata->destination, 1, &uri);
1239 "PJSIP REFER - Could not find endpoint '%s' and no default outbound endpoint configured\n",
1240 rdata->destination);
1245 refer_to_endpoint = ast_sip_get_endpoint(rdata->refer_to, 0, &tmp_str);
1247 ast_log(LOG_WARNING,
"PJSIP REFER - Refer to not a valid resource identifier or SIP URI\n");
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");
1256 refer->authentication_challenge_count = 0;
1257 refer->dlg = ast_sip_create_dialog_uac(endpoint, uri, NULL);
1259 ast_log(LOG_WARNING,
"PJSIP REFER - Could not create dialog\n");
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");
1276 snprintf(refer_to_str,
sizeof(refer_to_str),
"\"%s\" <%s>", disp_name_escaped, tmp_str);
1278 snprintf(refer_to_str,
sizeof(refer_to_str),
"%s", tmp_str);
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");
1290 if (refer_to_endpoint && rdata->to_self) {
1291 pjsip_dlg_add_usage(refer->dlg, &refer_out_of_dialog_module, rdata);
1294 ast_sip_update_to_uri(tdata, uri);
1295 ast_sip_update_from(tdata, rdata->from);
1301 vars_to_headers(rdata->refer, tdata);
1302 ast_debug(1,
"Sending REFER to '%s' (via endpoint %s) from '%s'\n",
1305 if (pjsip_xfer_send_request(sub, tdata) == PJ_SUCCESS) {
1311 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1312 pjsip_evsub_terminate(sub, PJ_FALSE);
1316 static int sip_refer_send(
const struct ast_refer *refer)
1318 struct refer_data *rdata;
1322 ast_log(LOG_ERROR,
"SIP REFER - a 'To' URI must be specified\n");
1326 rdata = refer_data_create(refer);
1339 .refer_send = sip_refer_send,
1342 static int refer_incoming_attended_request(
struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri,
1345 const pj_str_t str_replaces = {
"Replaces", 8 };
1346 pj_str_t replaces_content;
1347 pjsip_replaces_hdr *replaces;
1351 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
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",
1362 if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
1366 pjsip_dlg_dec_lock(dlg);
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",
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",
1381 if (ast_sip_session_defer_termination(session)) {
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);
1389 if (
ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {
1390 ast_sip_session_end_if_deferred(session);
1391 ast_sip_session_defer_termination_cancel(session);
1392 ao2_cleanup(attended);
1396 ast_debug(3,
"Attended transfer from '%s' pushed to second channel serializer\n",
1397 ast_channel_name(session->
channel));
1401 const char *context;
1405 DETERMINE_TRANSFER_CONTEXT(context, session);
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",
1420 if (ast_sip_session_defer_termination(session)) {
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),
1428 "external_replaces", context, refer_blind_callback, &refer));
1430 ast_sip_session_end_if_deferred(session);
1431 if (response != 200) {
1432 ast_sip_session_defer_termination_cancel(session);
1439 static int refer_incoming_blind_request(
struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
1448 DETERMINE_TRANSFER_CONTEXT(context, session);
1451 ast_copy_pj_str(exten, &target->user,
sizeof(exten));
1457 AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(exten);
1460 if (ast_strlen_zero(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",
1467 ast_log(LOG_ERROR,
"Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
1478 if (ast_sip_session_defer_termination(session)) {
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),
1486 exten, context, refer_blind_callback, &refer));
1488 ast_sip_session_end_if_deferred(session);
1489 if (response != 200) {
1490 ast_sip_session_defer_termination_cancel(session);
1522 static int refer_incoming_invite_request(
struct ast_sip_session *session,
struct pjsip_rx_data *rdata)
1524 pjsip_dialog *other_dlg = NULL;
1525 pjsip_tx_data *packet;
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;
1543 other_session = ast_sip_dialog_get_session(other_dlg);
1544 pjsip_dlg_dec_lock(other_dlg);
1547 if (session->
inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
1549 goto inv_replace_failed;
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",
1556 goto inv_replace_failed;
1559 invite.session = other_session;
1564 goto inv_replace_failed;
1567 ast_channel_lock(session->
channel);
1569 ast_channel_unlock(session->
channel);
1572 ast_debug(3,
"INVITE with Replaces being attempted. '%s' --> '%s'\n",
1573 ast_channel_name(session->
channel), ast_channel_name(invite.channel));
1579 if (!invite.bridge) {
1595 response = AST_CAUSE_FAILURE;
1600 response = AST_CAUSE_FAILURE;
1605 ao2_cleanup(invite.bridge);
1613 ast_debug(3,
"INVITE with Replaces successfully completed.\n");
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);
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);
1632 if (pjsip_inv_end_session(session->
inv_session, response, NULL, &packet) == PJ_SUCCESS
1634 ast_sip_session_send_response(session, packet);
1637 ast_debug(3,
"INVITE with Replaces in-dialog on channel '%s', hanging up\n",
1638 ast_channel_name(session->
channel));
1645 static int refer_incoming_refer_request(
struct ast_sip_session *session,
struct pjsip_rx_data *rdata)
1647 pjsip_generic_string_hdr *refer_to;
1651 pjsip_sip_uri *target_uri;
1653 pjsip_param *replaces;
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 };
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",
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",
1676 refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL);
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",
1688 uri_size = pj_strlen(&refer_to->hvalue) + 1;
1690 ast_copy_pj_str(uri, &refer_to->hvalue, uri_size);
1692 target = pjsip_parse_uri(rdata->tp_info.pool, uri, uri_size - 1, 0);
1695 || (!PJSIP_URI_SCHEME_IS_SIP(target)
1696 && !PJSIP_URI_SCHEME_IS_SIPS(target))) {
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",
1703 target_uri = pjsip_uri_get_uri(target);
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",
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);
1718 response = refer_incoming_blind_request(session, rdata, target_uri, progress);
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 };
1728 ast_debug(3,
"Progress monitoring not requested for REFER on channel '%s' from endpoint '%s', sending immediate response of '%d'\n",
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);
1736 hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
1737 pjsip_msg_add_hdr(tdata->msg, hdr);
1739 pjsip_dlg_send_response(session->
inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
1740 }
else if (response != 200) {
1742 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
1747 ao2_cleanup(notification);
1755 static int refer_incoming_request(
struct ast_sip_session *session, pjsip_rx_data *rdata)
1757 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
1758 return refer_incoming_refer_request(session, rdata);
1759 }
else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_invite_method)) {
1760 return refer_incoming_invite_request(session, rdata);
1780 static void add_header_from_channel_var(
struct ast_channel *chan,
const char *var_name,
const char *header_name, pjsip_tx_data *tdata)
1782 const char *var_value;
1783 pj_str_t pj_header_name;
1787 if (ast_strlen_zero(var_value)) {
1791 pj_cstr(&pj_header_name, header_name);
1792 header = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_header_name, NULL);
1796 ast_sip_add_header(tdata, header_name, var_value);
1799 static void refer_outgoing_request(
struct ast_sip_session *session,
struct pjsip_tx_data *tdata)
1801 if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method)
1803 || session->
inv_session->state != PJSIP_INV_STATE_NULL) {
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);
1814 .
priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1,
1815 .incoming_request = refer_incoming_request,
1816 .outgoing_request = refer_outgoing_request,
1819 static int load_module(
void)
1821 const pj_str_t str_norefersub = {
"norefersub", 10 };
1823 pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint());
1824 pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint());
1826 if (ast_sip_get_norefersub()) {
1827 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub);
1835 if (!refer_serializer) {
1840 ast_sip_register_service(&refer_out_of_dialog_module);
1841 ast_sip_register_service(&refer_progress_module);
1842 ast_sip_session_register_supplement(&refer_supplement);
1849 static int unload_module(
void)
1851 ast_sip_session_unregister_supplement(&refer_supplement);
1852 ast_sip_unregister_service(&refer_out_of_dialog_module);
1853 ast_sip_unregister_service(&refer_progress_module);
1859 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"PJSIP Blind and Attended Transfer Support",
1860 .support_level = AST_MODULE_SUPPORT_CORE,
1861 .load = load_module,
1862 .unload = unload_module,
1864 .requires =
"res_pjsip,res_pjsip_session,res_pjsip_pubsub",
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
pjsip_rx_data * rdata
Received packet, used to construct final response in case no subscription exists. ...
Main Channel structure associated with a channel.
struct ast_sip_endpoint * endpoint
Out-of-call refer support.
const char * ast_refer_get_to(const struct ast_refer *refer)
Retrieve the destination of this refer.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
struct refer_progress * progress
Refer progress structure to send notification on.
int subclass
Last received subclass in frame hook.
struct ast_channel_snapshot_base * base
Asterisk main include file. File version handling, generic pbx functions.
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
struct refer_progress * progress
Optional refer progress structure.
struct ast_sip_session * transferer
Transferer session.
struct ast_sip_session * transferer_second
Second transferer session.
struct ast_channel_snapshot * channel
#define ast_channel_unref(c)
Decrease channel reference count.
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
struct ast_taskprocessor * serializer
Serializer for notifications.
unsigned int defer_terminate
pjsip_evsub * sub
Subscription to provide updates on.
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
struct stasis_subscription * bridge_sub
Stasis subscription for bridge events.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
struct transfer_channel_data * transfer_data
Reference to transfer_channel_data related to the refer.
ast_framehook_event
These are the types of events that the framehook's event callback can receive.
Structure used to retrieve channel from another session.
Structure for blind transfer callback details.
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.
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Structure for attended transfer task.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int framehook
Frame hook for monitoring REFER progress.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
REFER Progress notification structure.
const ast_string_field uniqueid
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
unsigned int refer_blind_progress
Whether to notifies all the progress details on blind transfer.
#define ast_strdup(str)
A wrapper for strdup()
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.
int ast_channel_move(struct ast_channel *dest, struct ast_channel *source)
Move a channel from its current location to a new location.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
struct pjsip_inv_session * inv_session
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.
void ast_free_ptr(void *ptr)
free() wrapper
A structure describing a SIP session.
struct refer_progress * progress
Optional progress structure.
int ast_raw_answer(struct ast_channel *chan)
Answer a channel.
unsigned int attended
Attended transfer flag.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_frame_subclass subclass
struct ast_bridge * bridge
Bridge the channel is in.
char * transferee
Uniqueid of transferee channel.
const ast_string_field from
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
struct ast_bridge * ast_bridge_transfer_acquire_bridge(struct ast_channel *chan)
Acquire the channel's bridge for transfer purposes.
const char * context
Context being used for transfer.
pjsip_sip_uri * refer_to
Optional Refer-To header.
int ast_refer_tech_register(const struct ast_refer_tech *tech)
Register a refer technology.
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.
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)
#define ast_strdupa(s)
duplicate a string in memory from the stack
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.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
struct ast_refer * ast_refer_ref(struct ast_refer *refer)
Bump a refer's ref count.
struct ast_sip_endpoint * ast_sip_dialog_get_endpoint(pjsip_dialog *dlg)
Get the endpoint associated with this dialog.
#define AST_MAX_EXTENSION
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
#define ast_channel_cleanup(c)
Cleanup a channel reference.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
struct ast_refer_var_iterator * ast_refer_var_iterator_init(const struct ast_refer *refer)
Create a new refer variable iterator.
struct ast_channel * channel
#define ast_debug(level,...)
Log a DEBUG message.
An entity with which Asterisk communicates.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Blob of data associated with a bridge.
Core PBX routines and definitions.
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
void ast_refer_var_unref_current(struct ast_refer_var_iterator *iter)
Unref a refer var from inside an iterator loop.
struct ast_taskprocessor * serializer
struct ast_sip_session * session
Session we want the channel from.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Structure that contains information about a bridge.
const ast_string_field refer_to
Support for dynamic strings.
int ast_sip_thread_is_servant(void)
Determine if the current thread is a SIP servant thread.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
pjsip_replaces_hdr * replaces
Optional Replaces header.
void ast_refer_var_iterator_destroy(struct ast_refer_var_iterator *iter)
Destroy a refer variable iterator.
enum ast_sip_supplement_priority priority
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
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.
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
unsigned int refer_blind_progress
const char *const name
Name of this refer technology.
Module has failed to load, may be in an inconsistent state.
unsigned int allowtransfer
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.
int response
SIP response code to send.
An API for managing task processing threads that can be shared across modules.
int ast_refer_get_to_self(const struct ast_refer *refer)
Retrieve the "to_self" value of this refer.
A supplement to SIP message processing.
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...
struct ast_frame ast_null_frame
pjsip_rx_data * rdata
REFER message.
A ast_taskprocessor structure is a singleton by name.
#define ast_channel_ref(c)
Increase channel reference count.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
const char * ast_refer_get_from(const struct ast_refer *refer)
Retrieve the source of this refer.
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
struct ast_refer * ast_refer_destroy(struct ast_refer *refer)
Destroy an ast_refer.
AO2 object that wraps data for transfer_channel_cb.
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.
Data structure associated with a single frame of data.
Internal Asterisk hangup causes.
pjsip_dialog * dlg
Dialog for subscription.
int sent_100
Non-zero if the 100 notify has been sent.
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
enum ast_frame_type frametype
const char * ast_refer_get_refer_to(const struct ast_refer *refer)
Get the "refer-to" value of a refer.
struct ast_channel * transferer_chan
Transferer channel.
pjsip_evsub_state state
Subscription state.
#define ASTERISK_GPL_KEY
The text the key() function should return.
int ast_refer_tech_unregister(const struct ast_refer_tech *tech)
Unregister a refer technology.
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Asterisk module definitions.
REFER Progress structure.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
struct ast_channel * channel
Channel from the session (with reference)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.