Asterisk - The Open Source Telephony Project GIT-master-a358458
res_pjsip_refer.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*** MODULEINFO
20 <depend>pjproject</depend>
21 <depend>res_pjsip</depend>
22 <depend>res_pjsip_session</depend>
23 <depend>res_pjsip_pubsub</depend>
24 <support_level>core</support_level>
25 ***/
26
27#include "asterisk.h"
28
29#include <pjsip.h>
30#include <pjsip_ua.h>
31
32#include "asterisk/res_pjsip.h"
34#include "asterisk/module.h"
35#include "asterisk/pbx.h"
37#include "asterisk/bridge.h"
38#include "asterisk/framehook.h"
41#include "asterisk/causes.h"
42#include "asterisk/refer.h"
43
45
46static pj_status_t refer_on_tx_request(pjsip_tx_data *tdata);
47
48/*! \brief REFER Progress structure */
50 /*! \brief Subscription to provide updates on */
51 pjsip_evsub *sub;
52 /*! \brief Dialog for subscription */
53 pjsip_dialog *dlg;
54 /*! \brief Received packet, used to construct final response in case no subscription exists */
55 pjsip_rx_data *rdata;
56 /*! \brief Frame hook for monitoring REFER progress */
58 /*! \brief Last received subclass in frame hook */
60 /*! \brief Serializer for notifications */
62 /*! \brief Stasis subscription for bridge events */
64 /*! \brief Reference to transfer_channel_data related to the refer */
66 /*! \brief Uniqueid of transferee channel */
68 /*! \brief Non-zero if the 100 notify has been sent */
70 /*! \brief Whether to notifies all the progress details on blind transfer */
72};
73
74/*! \brief REFER Progress notification structure */
76 /*! \brief Refer progress structure to send notification on */
78 /*! \brief SIP response code to send */
80 /*! \brief Subscription state */
81 pjsip_evsub_state state;
82};
83
84/*! \brief REFER Progress module, used to attach REFER progress structure to subscriptions */
85static pjsip_module refer_progress_module = {
86 .name = { "REFER Progress", 14 },
87 .id = -1,
88};
89
90/*! \brief Destructor for REFER Progress notification structure */
92{
93 struct refer_progress_notification *notification = obj;
94
95 ao2_cleanup(notification->progress);
96}
97
98/*! \brief Allocator for REFER Progress notification structure */
100 pjsip_evsub_state state)
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}
115
116/*! \brief Serialized callback for subscription notification
117 *
118 * Locking and serialization:
119 *
120 * Although refer_progress_notify() always runs in the progress serializer,
121 * the pjproject evsub module itself can cause the subscription to be
122 * destroyed which then triggers refer_progress_on_evsub_state() to clean
123 * it up. In this case, it's possible that refer_progress_notify() could
124 * get the subscription pulled out from under it while it's trying to use it.
125 *
126 * At one point we tried to have refer_progress_on_evsub_state() push the
127 * cleanup to the serializer and wait for its return before returning to
128 * pjproject but since pjproject calls its state callbacks with the dialog
129 * locked, this required us to unlock the dialog while waiting for the
130 * serialized cleanup, then lock it again before returning to pjproject.
131 * There were also still some cases where other callers of
132 * refer_progress_notify() weren't using the serializer and crashes were
133 * resulting.
134 *
135 * Although all callers of refer_progress_notify() now use the progress
136 * serializer, we decided to simplify the locking so we didn't have to
137 * unlock and relock the dialog in refer_progress_on_evsub_state().
138 *
139 * Now, refer_progress_notify() holds the dialog lock for all its work
140 * rather than just when calling pjsip_evsub_set_mod_data() to clear the
141 * module data. Since pjproject also holds the dialog lock while calling
142 * refer_progress_on_evsub_state(), there should be no more chances for
143 * the subscription to be cleaned up while still being used to send NOTIFYs.
144 */
145static int refer_progress_notify(void *data)
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}
185
186static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
187 struct stasis_message *message)
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}
239
240/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer */
241static struct ast_frame *refer_progress_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
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}
300
301/*! \brief Destroy callback for monitoring framehook */
302static void refer_progress_framehook_destroy(void *data)
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}
317
318/*!
319 * \brief Callback for REFER subscription state changes
320 * \see refer_progress_notify
321 *
322 * The documentation attached to refer_progress_notify has more
323 * information about the locking issues with cleaning up
324 * the subscription.
325 *
326 * \note pjproject holds the dialog lock while calling this function.
327 */
328static void refer_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
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}
342
343/*! \brief Callback structure for subscription */
344static pjsip_evsub_user refer_progress_evsub_cb = {
345 .on_evsub_state = refer_progress_on_evsub_state,
346};
347
348static int dlg_releaser_task(void *data) {
349 pjsip_dlg_dec_session((pjsip_dialog *)data, &refer_progress_module);
350 return 0;
351}
352
353/*! \brief Destructor for REFER progress sutrcture */
354static void refer_progress_destroy(void *obj)
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}
385
386/*! \brief Internal helper function which sets up a refer progress structure if needed */
387static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata, struct refer_progress **progress)
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}
455
456/*! \brief Structure for attended transfer task */
458 /*! \brief Transferer session */
460 /*! \brief Transferer channel */
462 /*! \brief Second transferer session */
464 /*! \brief Optional refer progress structure */
466};
467
468/*! \brief Destructor for attended transfer task */
469static void refer_attended_destroy(void *obj)
470{
471 struct refer_attended *attended = obj;
472
473 ao2_cleanup(attended->transferer);
476 ao2_cleanup(attended->progress);
477}
478
479/*! \brief Allocator for attended transfer task */
482 struct refer_progress *progress)
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}
506
507static int session_end_if_deferred_task(void *data)
508{
509 struct ast_sip_session *session = data;
510
512 ao2_ref(session, -1);
513 return 0;
514}
515
516static int defer_termination_cancel_task(void *data)
517{
518 struct ast_sip_session *session = data;
519
522 ao2_ref(session, -1);
523 return 0;
524}
525
526/*!
527 * \internal
528 * \brief Convert transfer enum to SIP response code.
529 * \since 13.3.0
530 *
531 * \param xfer_code Core transfer function enum result.
532 *
533 * \return SIP response code
534 */
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}
556
557/*! \brief Task for attended transfer executed by attended->transferer_second serializer */
558static int refer_attended_task(void *data)
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}
612
613/*! \brief Structure for blind transfer callback details */
615 /*! \brief Context being used for transfer */
616 const char *context;
617 /*! \brief Optional progress structure */
619 /*! \brief REFER message */
620 pjsip_rx_data *rdata;
621 /*! \brief Optional Replaces header */
622 pjsip_replaces_hdr *replaces;
623 /*! \brief Optional Refer-To header */
624 pjsip_sip_uri *refer_to;
625 /*! \brief Attended transfer flag */
626 unsigned int attended:1;
627};
628
629/*! \brief Blind transfer callback function */
630static void refer_blind_callback(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
631 enum ast_transfer_type transfer_type)
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}
828
829/*!
830 * \internal
831 * \brief Set the passed in context variable to the determined transfer context.
832 * \since 13.3.0
833 *
834 * \param context Set to the determined transfer context.
835 * \param session INVITE dialog SIP session.
836 */
837#define DETERMINE_TRANSFER_CONTEXT(context, session) \
838 do { \
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; \
843 } else { \
844 context = ast_strdupa(context); \
845 } \
846 ast_channel_unlock((session)->channel); \
847 } while (0) \
848
849struct refer_data {
852 char *from;
853 char *refer_to;
855};
856
857static void refer_data_destroy(void *obj)
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}
867
868static struct refer_data *refer_data_create(const struct ast_refer *refer)
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}
919
920/*!
921 * \internal
922 * \brief Checks if the given refer var name should be blocked.
923 *
924 * \details Some headers are not allowed to be overridden by the user.
925 * Determine if the given var header name from the user is blocked for
926 * an outgoing REFER.
927 *
928 * \param name name of header to see if it is blocked.
929 *
930 * \retval TRUE if the given header is blocked.
931 */
932static int is_refer_var_blocked(const char *name)
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}
959
960/*!
961 * \internal
962 * \brief Copies any other refer vars over to the request headers.
963 *
964 * \param refer The refer structure to copy headers from
965 * \param tdata The SIP transmission data
966 */
967static enum pjsip_status_code vars_to_headers(const struct ast_refer *refer, pjsip_tx_data *tdata)
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}
984
986 pjsip_dialog *dlg;
988};
989
990/*! \brief REFER Out-of-dialog module, used to attach session data structure to subscription */
991static pjsip_module refer_out_of_dialog_module = {
992 .name = { "REFER Out-of-dialog Module", 26 },
993 .id = -1,
994 .on_tx_request = refer_on_tx_request,
995 /* Ensure that we are called after res_pjsp_nat module and before transport priority */
996 .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 4,
997};
998
999/*! \brief Helper function which returns the name-addr of the Refer-To header or NULL */
1000static pjsip_uri *get_refer_to_uri(pjsip_tx_data *tdata)
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}
1014
1015static pj_status_t refer_on_tx_request(pjsip_tx_data *tdata) {
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}
1049
1050static int refer_unreference_dialog(void *obj)
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}
1066/*! \brief Destructor for REFER out of dialog structure */
1067static void refer_out_of_dialog_destroy(void *obj) {
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}
1077
1078/*!
1079 * \internal
1080 * \brief Callback function to report status of implicit REFER-NOTIFY subscription.
1081 *
1082 * This function will be called on any state change in the REFER-NOTIFY subscription.
1083 * Its primary purpose is to report SUCCESS/FAILURE of a refer initiated via
1084 * \ref refer_send as well as to terminate the subscription, if necessary.
1085 */
1086static void refer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
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}
1211
1212/*!
1213 * \internal
1214 * \brief Send a REFER
1215 *
1216 * \param data The outbound refer data structure
1217 *
1218 * \return 0: success, -1: failure
1219 */
1220static int refer_send(void *data)
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}
1315
1316static int sip_refer_send(const struct ast_refer *refer)
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}
1336
1337static const struct ast_refer_tech refer_tech = {
1338 .name = "pjsip",
1339 .refer_send = sip_refer_send,
1340};
1341
1342static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri,
1343 pjsip_param *replaces_param, struct refer_progress *progress)
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}
1438
1439static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
1440 struct refer_progress *progress)
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}
1495
1496/*! \brief Structure used to retrieve channel from another session */
1498 /*! \brief Session we want the channel from */
1500 /*! \brief Channel from the session (with reference) */
1502 /*! \brief Bridge the channel is in */
1504};
1505
1506/*! \brief Task for invite replaces */
1507static int invite_replaces(void *data)
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}
1521
1522static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
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",
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}
1644
1645static int refer_incoming_refer_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
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}
1754
1755static int refer_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
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}
1765
1766/*!
1767 * \brief Use the value of a channel variable as the value of a SIP header
1768 *
1769 * This looks up a variable name on a channel, then takes that value and adds
1770 * it to an outgoing SIP request. If the header already exists on the message,
1771 * then no action is taken.
1772 *
1773 * \pre chan is locked.
1774 *
1775 * \param chan The channel on which to find the variable.
1776 * \param var_name The name of the channel variable to use.
1777 * \param header_name The name of the SIP header to add to the outgoing message.
1778 * \param tdata The outgoing SIP message on which to add the header
1779 */
1780static void add_header_from_channel_var(struct ast_channel *chan, const char *var_name, const char *header_name, pjsip_tx_data *tdata)
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}
1798
1799static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
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}
1812
1815 .incoming_request = refer_incoming_request,
1816 .outgoing_request = refer_outgoing_request,
1817};
1818
1819static int load_module(void)
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}
1848
1849static int unload_module(void)
1850{
1855
1856 return 0;
1857}
1858
1859AST_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,
1863 .load_pri = AST_MODPRI_APP_DEPEND,
1864 .requires = "res_pjsip,res_pjsip_session,res_pjsip_pubsub",
jack_status_t status
Definition: app_jack.c:146
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#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
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_log
Definition: astobj2.c:42
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
Bridging API.
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
struct ast_bridge * ast_bridge_transfer_acquire_bridge(struct ast_channel *chan)
Acquire the channel's bridge for transfer purposes.
Definition: bridge.c:4408
ast_transfer_type
Definition: bridge.h:1109
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
ast_transfer_result
Definition: bridge.h:1098
@ 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
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition: bridge.h:590
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
static int tmp()
Definition: bt_open.c:389
Internal Asterisk hangup causes.
#define AST_CAUSE_FAILURE
Definition: causes.h:150
enum cc_state state
Definition: ccss.c:393
const char * ast_channel_name(const struct ast_channel *chan)
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
#define ast_channel_lock(chan)
Definition: channel.h:2922
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2947
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
const char * ast_channel_uniqueid(const struct ast_channel *chan)
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)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
#define ast_channel_unlock(chan)
Definition: channel.h:2923
#define AST_MAX_EXTENSION
Definition: channel.h:134
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
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
FrameHook Architecture.
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
ast_framehook_event
These are the types of events that the framehook's event callback can receive.
Definition: framehook.h:151
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
#define AST_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.
struct ast_sip_endpoint * ast_sip_dialog_get_endpoint(pjsip_dialog *dlg)
Get the endpoint associated with this dialog.
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
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2094
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_sip_thread_is_servant(void)
Determine if the current thread is a SIP servant thread.
Definition: res_pjsip.c:2310
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
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
static char prefix[MAX_PREFIX]
Definition: http.c:144
@ 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 ast_null_frame
Definition: main/frame.c:79
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:464
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_APP_DEPEND
Definition: module.h:328
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ 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
Core PBX routines and definitions.
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_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
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.
Out-of-call refer support.
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_tech_unregister(const struct ast_refer_tech *tech)
Unregister a refer technology.
Definition: refer.c:490
const char * ast_refer_get_to(const struct ast_refer *refer)
Retrieve the destination of this refer.
Definition: refer.c:229
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
const char * ast_refer_get_from(const struct ast_refer *refer)
Retrieve the source of this refer.
Definition: refer.c:224
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_refer * ast_refer_destroy(struct ast_refer *refer)
Destroy an ast_refer.
Definition: refer.c:152
const char * ast_refer_get_refer_to(const struct ast_refer *refer)
Get the "refer-to" value of a refer.
Definition: refer.c:219
int ast_refer_tech_register(const struct ast_refer_tech *tech)
Register a refer technology.
Definition: refer.c:446
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
void ast_refer_var_iterator_destroy(struct ast_refer_var_iterator *iter)
Destroy a refer variable iterator.
Definition: refer.c:376
struct stasis_forward * sub
Definition: res_corosync.c:240
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
unsigned int ast_sip_get_norefersub(void)
Retrieve the global setting 'norefersub'.
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:133
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:117
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_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
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
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3351
int ast_sip_update_from(pjsip_tx_data *tdata, char *from)
Overwrite fields in the outbound 'From' header.
Definition: res_pjsip.c:3383
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition: res_pjsip.h:3186
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
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
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
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 MAX_RX_CHALLENGES
Definition: res_pjsip.h:110
static int refer_unreference_dialog(void *obj)
static void refer_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
Callback for REFER subscription state changes.
static void add_header_from_channel_var(struct ast_channel *chan, const char *var_name, const char *header_name, pjsip_tx_data *tdata)
Use the value of a channel variable as the value of a SIP header.
static void refer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
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 int xfer_response_code2sip(enum ast_transfer_result xfer_code)
static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static struct refer_data * refer_data_create(const struct ast_refer *refer)
static void refer_progress_notification_destroy(void *obj)
Destructor for REFER Progress notification structure.
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 struct ast_sip_session_supplement refer_supplement
static pjsip_module refer_progress_module
REFER Progress module, used to attach REFER progress structure to subscriptions.
static int dlg_releaser_task(void *data)
static enum pjsip_status_code vars_to_headers(const struct ast_refer *refer, pjsip_tx_data *tdata)
static int is_refer_var_blocked(const char *name)
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)
#define DETERMINE_TRANSFER_CONTEXT(context, session)
static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target, struct refer_progress *progress)
static const struct ast_refer_tech refer_tech
static int refer_progress_notify(void *data)
Serialized callback for subscription notification.
static int refer_incoming_invite_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 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_incoming_refer_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
static void refer_attended_destroy(void *obj)
Destructor for attended transfer task.
static int sip_refer_send(const struct ast_refer *refer)
static int refer_attended_task(void *data)
Task for attended transfer executed by attended->transferer_second serializer.
static pj_status_t refer_on_tx_request(pjsip_tx_data *tdata)
static void refer_progress_destroy(void *obj)
Destructor for REFER progress sutrcture.
static int refer_send(void *data)
static int defer_termination_cancel_task(void *data)
static int invite_replaces(void *data)
Task for invite replaces.
static void refer_out_of_dialog_destroy(void *obj)
Destructor for REFER out of dialog structure.
static int session_end_if_deferred_task(void *data)
static int load_module(void)
static void refer_progress_framehook_destroy(void *data)
Destroy callback for monitoring framehook.
static int unload_module(void)
static pjsip_uri * get_refer_to_uri(pjsip_tx_data *tdata)
Helper function which returns the name-addr of the Refer-To header or NULL.
static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata, struct refer_progress **progress)
Internal helper function which sets up a refer progress structure if needed.
static 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 pjsip_evsub_user refer_progress_evsub_cb
Callback structure for subscription.
static void refer_progress_bridge(void *data, struct stasis_subscription *sub, struct stasis_message *message)
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.
static void refer_data_destroy(void *obj)
struct ast_sip_session * ast_sip_dialog_get_session(pjsip_dialog *dlg)
Retrieves a session from a dialog.
void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session)
Cancel a pending deferred termination.
#define ast_sip_session_register_supplement(supplement)
void ast_sip_session_end_if_deferred(struct ast_sip_session *session)
End the session if it had been previously deferred.
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
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.
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
#define NULL
Definition: resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_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
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
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
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
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
Blob of data associated with a bridge.
struct ast_channel_snapshot * channel
Structure that contains information about a bridge.
Definition: bridge.h:349
const ast_string_field uniqueid
struct ast_channel_snapshot_base * base
Main Channel structure associated with a channel.
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
struct ast_module * self
Definition: module.h:342
A refer technology.
Definition: refer.h:52
const char *const name
Name of this refer technology.
Definition: refer.h:61
struct ao2_iterator iter
Definition: refer.c:331
A refer.
Definition: refer.c:57
An entity with which Asterisk communicates.
Definition: res_pjsip.h:963
A supplement to SIP message processing.
enum ast_sip_supplement_priority priority
A structure describing a SIP session.
struct ast_channel * channel
struct ast_taskprocessor * serializer
Support for dynamic strings.
Definition: strings.h:623
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
Definition: astman.c:222
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.
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.
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.
char * destination
struct ast_refer * refer
pjsip_dialog * dlg
REFER Progress notification structure.
pjsip_evsub_state state
Subscription state.
int response
SIP response code to send.
struct refer_progress * progress
Refer progress structure to send notification on.
REFER Progress structure.
struct transfer_channel_data * transfer_data
Reference to transfer_channel_data related to the refer.
pjsip_rx_data * rdata
Received packet, used to construct final response in case no subscription exists.
unsigned int refer_blind_progress
Whether to notifies all the progress details on blind transfer.
pjsip_evsub * sub
Subscription to provide updates on.
int subclass
Last received subclass in frame hook.
pjsip_dialog * dlg
Dialog for subscription.
struct stasis_subscription * bridge_sub
Stasis subscription for bridge events.
struct ast_taskprocessor * serializer
Serializer for notifications.
int sent_100
Non-zero if the 100 notify has been sent.
char * transferee
Uniqueid of transferee channel.
int framehook
Frame hook for monitoring REFER progress.
AO2 object that wraps data for transfer_channel_cb.
Definition: bridge.h:1119
int value
Definition: syslog.c:37
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
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
FILE * out
Definition: utils/frame.c:33
int error(const char *format,...)
Definition: utils/frame.c:999
#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
#define ast_assert(a)
Definition: utils.h:739
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
Definition: utils.c:781
#define ARRAY_LEN(a)
Definition: utils.h:666