Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
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);
47static int defer_termination_cancel_task(void *data);
48
50 /*! \brief A deferred session used by the ARI only mode */
53
55
58
62};
63
64/*! \brief REFER Progress structure */
66 /*! \brief Subscription to provide updates on */
67 pjsip_evsub *sub;
68 /*! \brief Dialog for subscription */
69 pjsip_dialog *dlg;
70 /*! \brief Received packet, used to construct final response in case no subscription exists */
71 pjsip_rx_data *rdata;
72 /*! \brief Frame hook for monitoring REFER progress */
74 /*! \brief Last received subclass in frame hook */
76 /*! \brief Serializer for notifications */
78 /*! \brief Stasis subscription for bridge events */
80 /*! \brief Reference to transfer_channel_data related to the refer */
82 /*! \brief Uniqueid of transferee channel */
84 /*! \brief Non-zero if the 100 notify has been sent */
86 /*! \brief Whether to notifies all the progress details on blind transfer */
88 /*! \brief State related to the transfer in ARI only mode */
90};
91
92/*! \brief REFER Progress notification structure */
94 /*! \brief Refer progress structure to send notification on */
96 /*! \brief SIP response code to send */
98 /*! \brief Subscription state */
99 pjsip_evsub_state state;
100};
101
102/*! \brief REFER Progress module, used to attach REFER progress structure to subscriptions */
103static pjsip_module refer_progress_module = {
104 .name = { "REFER Progress", 14 },
105 .id = -1,
106};
107
108/*! \brief Destructor of the state used for the ARI transfer */
109static void transfer_ari_state_destroy(void *obj)
110{
111 struct transfer_ari_state *state = obj;
112
113 ao2_cleanup(state->transferer);
114 ao2_cleanup(state->other_session);
115 ast_channel_cleanup(state->transferer_chan);
116 ast_free(state->referred_by);
117 ast_free(state->protocol_id);
118 ao2_cleanup(state->params);
119}
120
121static void refer_params_destroy(void *obj)
122{
123 struct ast_refer_params *params = obj;
124
125 for (int i = 0; i < AST_VECTOR_SIZE(params); ++i) {
126 struct ast_refer_param param = AST_VECTOR_GET(params, i);
127 ast_free((char *) param.param_name);
128 ast_free((char *) param.param_value);
129 }
130}
131
132/*! \brief Destructor for REFER Progress notification structure */
134{
135 struct refer_progress_notification *notification = obj;
136
137 ao2_cleanup(notification->progress);
138}
139
141{
142 return ast_refer_notify_transfer_request(state->transferer_chan, state->referred_by,
143 state->exten, state->protocol_id,
144 state->other_session ? state->other_session->channel : NULL,
145 state->params, state->last_response);
146}
147
148/*! \brief Allocator for REFER Progress notification structure */
150 pjsip_evsub_state state)
151{
152 struct refer_progress_notification *notification = ao2_alloc(sizeof(*notification), refer_progress_notification_destroy);
153
154 if (!notification) {
155 return NULL;
156 }
157
158 ao2_ref(progress, +1);
159 notification->progress = progress;
160 notification->response = response;
161 notification->state = state;
162
163 return notification;
164}
165
166/*! \brief Serialized callback for subscription notification
167 *
168 * Locking and serialization:
169 *
170 * Although refer_progress_notify() always runs in the progress serializer,
171 * the pjproject evsub module itself can cause the subscription to be
172 * destroyed which then triggers refer_progress_on_evsub_state() to clean
173 * it up. In this case, it's possible that refer_progress_notify() could
174 * get the subscription pulled out from under it while it's trying to use it.
175 *
176 * At one point we tried to have refer_progress_on_evsub_state() push the
177 * cleanup to the serializer and wait for its return before returning to
178 * pjproject but since pjproject calls its state callbacks with the dialog
179 * locked, this required us to unlock the dialog while waiting for the
180 * serialized cleanup, then lock it again before returning to pjproject.
181 * There were also still some cases where other callers of
182 * refer_progress_notify() weren't using the serializer and crashes were
183 * resulting.
184 *
185 * Although all callers of refer_progress_notify() now use the progress
186 * serializer, we decided to simplify the locking so we didn't have to
187 * unlock and relock the dialog in refer_progress_on_evsub_state().
188 *
189 * Now, refer_progress_notify() holds the dialog lock for all its work
190 * rather than just when calling pjsip_evsub_set_mod_data() to clear the
191 * module data. Since pjproject also holds the dialog lock while calling
192 * refer_progress_on_evsub_state(), there should be no more chances for
193 * the subscription to be cleaned up while still being used to send NOTIFYs.
194 */
195static int refer_progress_notify(void *data)
196{
197 RAII_VAR(struct refer_progress_notification *, notification, data, ao2_cleanup);
198 pjsip_evsub *sub;
199 pjsip_tx_data *tdata;
200
201 pjsip_dlg_inc_lock(notification->progress->dlg);
202
203 /* If the subscription has already been terminated we can't send a notification */
204 if (!(sub = notification->progress->sub)) {
205 ast_debug(3, "Not sending NOTIFY of response '%d' and state '%u' on progress monitor '%p' as subscription has been terminated\n",
206 notification->response, notification->state, notification->progress);
207 pjsip_dlg_dec_lock(notification->progress->dlg);
208 return 0;
209 }
210
211 /* Send a deferred initial 100 Trying SIP frag NOTIFY if we haven't already. */
212 if (!notification->progress->sent_100) {
213 notification->progress->sent_100 = 1;
214 if (notification->response != 100) {
215 ast_debug(3, "Sending initial 100 Trying NOTIFY for progress monitor '%p'\n",
216 notification->progress);
217 if (pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) {
218 pjsip_xfer_send_request(sub, tdata);
219 }
220 }
221 }
222
223 ast_debug(3, "Sending NOTIFY with response '%d' and state '%u' on subscription '%p' and progress monitor '%p'\n",
224 notification->response, notification->state, sub, notification->progress);
225
226 /* Actually send the notification */
227 if (pjsip_xfer_notify(sub, notification->state, notification->response, NULL, &tdata) == PJ_SUCCESS) {
228 pjsip_xfer_send_request(sub, tdata);
229 }
230
231
232 if (notification->progress->ari_state) {
233 struct transfer_ari_state *ari_state = notification->progress->ari_state;
234 ari_notify(ari_state);
235 }
236
237 pjsip_dlg_dec_lock(notification->progress->dlg);
238
239 return 0;
240}
241
242static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
243 struct stasis_message *message)
244{
245 struct refer_progress *progress = data;
246 struct ast_bridge_blob *enter_blob;
247 struct refer_progress_notification *notification;
248 struct ast_channel *chan;
249
251 ao2_ref(progress, -1);
252 return;
253 }
254
256 /* Don't care */
257 return;
258 }
259
260 enter_blob = stasis_message_data(message);
261 if (strcmp(enter_blob->channel->base->uniqueid, progress->transferee)) {
262 /* Don't care */
263 return;
264 }
265
266 if (!progress->transfer_data->completed) {
267 /* We can't act on this message because the transfer_channel_data doesn't show that
268 * the transfer is ready to progress */
269 return;
270 }
271
272 /* OMG the transferee is joining a bridge. His call got answered! */
273 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
274 if (notification) {
275 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
276 ao2_cleanup(notification);
277 }
278 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
279 }
280
281 chan = ast_channel_get_by_name(progress->transferee);
282 if (!chan) {
283 /* The channel is already gone */
284 return;
285 }
286
287 ast_channel_lock(chan);
288 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as it has joined a bridge\n",
289 ast_channel_name(chan));
290 ast_framehook_detach(chan, progress->framehook);
291 ast_channel_unlock(chan);
292
293 ast_channel_unref(chan);
294}
295
296/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer */
297static struct ast_frame *refer_progress_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
298{
299 struct refer_progress *progress = data;
300 struct refer_progress_notification *notification = NULL;
301
302 /* We only care about frames *to* the channel */
303 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
304 return f;
305 }
306
307 /* If the completed flag hasn't been raised, skip this pass. */
308 if (!progress->transfer_data->completed) {
309 return f;
310 }
311
312 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
313 if (f->frametype == AST_FRAME_VOICE && !progress->subclass) {
314 /* Media is passing without progress, this means the call has been answered */
315 progress->subclass = AST_CONTROL_ANSWER;
316 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
317 } else if (f->frametype == AST_FRAME_CONTROL) {
318 /* Based on the control frame being written we can send a NOTIFY advising of the progress */
320 /* Don't set progress->subclass; an ANSWER can still follow */
321 notification = refer_progress_notification_alloc(progress, 180, PJSIP_EVSUB_STATE_ACTIVE);
322 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
323 progress->subclass = f->subclass.integer;
324 notification = refer_progress_notification_alloc(progress, 486, PJSIP_EVSUB_STATE_TERMINATED);
325 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
326 progress->subclass = f->subclass.integer;
327 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
328 } else if (f->subclass.integer == AST_CONTROL_PROGRESS) {
329 /* Don't set progress->subclass; an ANSWER can still follow */
330 notification = refer_progress_notification_alloc(progress, 183, PJSIP_EVSUB_STATE_ACTIVE);
331 } else if (f->subclass.integer == AST_CONTROL_PROCEEDING) {
332 /* Don't set progress->subclass; an ANSWER can still follow */
333 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
334 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
335 progress->subclass = f->subclass.integer;
336 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
337 }
338 }
339
340 /* If a notification is due to be sent push it to the taskpool */
341 if (notification) {
342 /* If the subscription is being terminated we don't need the frame hook any longer */
343 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
344 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
345 ast_channel_name(chan));
346 ast_framehook_detach(chan, progress->framehook);
347 }
348
349 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
350 ao2_cleanup(notification);
351 }
352 }
353
354 return f;
355}
356
357/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer. Used for the ari-only mode */
359{
360 struct refer_progress *progress = data;
361 struct refer_progress_notification *notification = NULL;
362
363 /* We only care about frames *to* the channel */
364 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
365 return f;
366 }
367
368 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
371 && f->datalen >= sizeof(enum ast_control_transfer)) {
373 switch (*message) {
375 notification = refer_progress_notification_alloc(progress, 603, PJSIP_EVSUB_STATE_TERMINATED);
376 break;
378 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
379 break;
381 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
382 break;
384 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
385 break;
387 break;
388 }
389 progress->ari_state->last_response = *message;
390 }
391
392 /* If a notification is due to be sent push it to the taskpool */
393 if (notification) {
394 /* If the subscription is being terminated we don't need the frame hook any longer */
395 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
396 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
397 ast_channel_name(chan));
398 ast_framehook_detach(chan, progress->framehook);
399 }
400
401 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
402 ao2_cleanup(notification);
403 }
404 }
405
406 return f;
407}
408
409/*! \brief Destroy callback for monitoring framehook */
410static void refer_progress_framehook_destroy(void *data)
411{
412 struct refer_progress *progress = data;
413 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
414
415 if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
416 ao2_cleanup(notification);
417 }
418
419 if (progress->bridge_sub) {
420 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
421 }
422
424}
425
426/*!
427 * \brief Callback for REFER subscription state changes
428 * \see refer_progress_notify
429 *
430 * The documentation attached to refer_progress_notify has more
431 * information about the locking issues with cleaning up
432 * the subscription.
433 *
434 * \note pjproject holds the dialog lock while calling this function.
435 */
436static void refer_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
437{
438 struct refer_progress *progress = pjsip_evsub_get_mod_data(sub, refer_progress_module.id);
439
440 /*
441 * If being destroyed, remove the progress object from the subscription
442 * and release the reference it had.
443 */
444 if (progress && (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)) {
445 pjsip_evsub_set_mod_data(progress->sub, refer_progress_module.id, NULL);
446 progress->sub = NULL;
448 }
449}
450
451/*! \brief Callback structure for subscription */
452static pjsip_evsub_user refer_progress_evsub_cb = {
453 .on_evsub_state = refer_progress_on_evsub_state,
454};
455
456static int dlg_releaser_task(void *data) {
457 pjsip_dlg_dec_session((pjsip_dialog *)data, &refer_progress_module);
458 return 0;
459}
460
461/*! \brief Destructor for REFER progress sutrcture */
462static void refer_progress_destroy(void *obj)
463{
464 struct refer_progress *progress = obj;
465
466 if (progress->bridge_sub) {
467 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
468 }
469
470 if (progress->dlg) {
471 /*
472 * Although the dlg session count was incremented in a pjsip servant
473 * thread, there's no guarantee that the last thread to unref this progress
474 * object was one. Before we decrement, we need to make sure that this
475 * is either a servant thread or that we push the decrement to a
476 * serializer that is one.
477 *
478 * Because pjsip_dlg_dec_session requires the dialog lock, we don't want
479 * to wait on the task to complete if we had to push it to a serializer.
480 */
482 pjsip_dlg_dec_session(progress->dlg, &refer_progress_module);
483 } else {
485 }
486 }
487
488 ao2_cleanup(progress->transfer_data);
489 ao2_cleanup(progress->ari_state);
490
491 ast_free(progress->transferee);
493}
494
495/*! \brief Internal helper function which sets up a refer progress structure if needed */
496static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata, struct refer_progress **progress)
497{
498 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
499 pjsip_generic_string_hdr *refer_sub = NULL;
500 const pj_str_t str_true = { "true", 4 };
501 pjsip_hdr hdr_list;
502 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
503
504 *progress = NULL;
505
506 /* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */
507 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
508 if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4))) {
509 return 0;
510 }
511
512 if (!(*progress = ao2_alloc(sizeof(struct refer_progress), refer_progress_destroy))) {
513 return -1;
514 }
515
516 ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
518
519 (*progress)->refer_blind_progress = session->endpoint->refer_blind_progress;
520
521 (*progress)->framehook = -1;
522
523 /* Create name with seq number appended. */
524 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/refer/%s",
526
527 if (!((*progress)->serializer = ast_sip_create_serializer(tps_name))) {
528 goto error;
529 }
530
531 /* Create the implicit subscription for monitoring of this transfer */
532 if (pjsip_xfer_create_uas(session->inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
533 goto error;
534 }
535
536 /* To prevent a potential deadlock we need the dialog so we can lock/unlock */
537 (*progress)->dlg = session->inv_session->dlg;
538 /* We also need to make sure it stays around until we're done with it */
539 pjsip_dlg_inc_session((*progress)->dlg, &refer_progress_module);
540
541
542 /* Associate the REFER progress structure with the subscription */
543 ao2_ref(*progress, +1);
544 pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
545
546 pj_list_init(&hdr_list);
547 if (refer_sub) {
548 pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->inv_session->dlg->pool, &str_refer_sub, &str_true);
549
550 pj_list_push_back(&hdr_list, hdr);
551 }
552
553 /* Accept the REFER request */
554 ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress);
555 pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
556
557 return 0;
558
559error:
561 *progress = NULL;
562 return -1;
563}
564
565/*! \brief Structure for attended transfer task */
567 /*! \brief Transferer session */
569 /*! \brief Transferer channel */
571 /*! \brief Second transferer session */
573 /*! \brief Optional refer progress structure */
575};
576
577/*! \brief Destructor for attended transfer task */
578static void refer_attended_destroy(void *obj)
579{
580 struct refer_attended *attended = obj;
581
582 ao2_cleanup(attended->transferer);
585 ao2_cleanup(attended->progress);
586}
587
588/*! \brief Allocator for attended transfer task */
591 struct refer_progress *progress)
592{
593 struct refer_attended *attended;
594
595 attended = ao2_alloc_options(sizeof(*attended), refer_attended_destroy,
597 if (!attended) {
598 return NULL;
599 }
600
601 ao2_ref(transferer, +1);
602 attended->transferer = transferer;
607
608 if (progress) {
609 ao2_ref(progress, +1);
610 attended->progress = progress;
611 }
612
613 return attended;
614}
615
616static int session_end_if_deferred_task(void *data)
617{
618 struct ast_sip_session *session = data;
619
621 ao2_ref(session, -1);
622 return 0;
623}
624
634
635/*!
636 * \internal
637 * \brief Convert transfer enum to SIP response code.
638 * \since 13.3.0
639 *
640 * \param xfer_code Core transfer function enum result.
641 *
642 * \return SIP response code
643 */
645{
646 int response;
647
648 response = 503;
649 switch (xfer_code) {
651 response = 400;
652 break;
654 response = 403;
655 break;
657 response = 500;
658 break;
660 response = 200;
661 break;
662 }
663 return response;
664}
665
666/*! \brief Task for attended transfer executed by attended->transferer_second serializer */
667static int refer_attended_task(void *data)
668{
669 struct refer_attended *attended = data;
670 int response;
671 int (*task_cb)(void *data);
672
673 if (attended->transferer_second->channel) {
674 ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
677
679 attended->transferer_chan,
680 attended->transferer_second->channel));
681
682 ast_debug(3, "Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
685 response);
686 } else {
687 ast_debug(3, "Received REFER request on channel '%s' but other channel has gone.\n",
689 response = 603;
690 }
691
692 if (attended->progress) {
693 struct refer_progress_notification *notification;
694
695 notification = refer_progress_notification_alloc(attended->progress, response,
696 PJSIP_EVSUB_STATE_TERMINATED);
697 if (notification) {
698 if (ast_sip_push_task(attended->progress->serializer, refer_progress_notify, notification)) {
699 ao2_cleanup(notification);
700 }
701 }
702 }
703
704 if (response == 200) {
706 } else {
708 }
710 task_cb, attended->transferer)) {
711 /* Gave the ref to the pushed task. */
712 attended->transferer = NULL;
713 } else {
714 /* Do this anyway even though it is the wrong serializer. */
716 }
717
718 ao2_ref(attended, -1);
719 return 0;
720}
721
722/*! \brief Structure for blind transfer callback details */
724 /*! \brief Context being used for transfer */
725 const char *context;
726 /*! \brief Optional progress structure */
728 /*! \brief REFER message */
729 pjsip_rx_data *rdata;
730 /*! \brief Optional Replaces header */
731 pjsip_replaces_hdr *replaces;
732 /*! \brief Optional Refer-To header */
733 pjsip_sip_uri *refer_to;
734 /*! \brief Attended transfer flag */
735 unsigned int attended:1;
736};
737
738/*! \brief Blind transfer callback function */
739static void refer_blind_callback(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
740 enum ast_transfer_type transfer_type)
741{
742 struct refer_blind *refer = user_data_wrapper->data;
743 pjsip_generic_string_hdr *referred_by;
744
745 static const pj_str_t str_referred_by = { "Referred-By", 11 };
746 static const pj_str_t str_referred_by_s = { "b", 1 };
747 const char *get_xfrdata;
748
749 pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
750
751 if (refer->progress && !refer->attended && !refer->progress->refer_blind_progress) {
752 /* If blind transfer and endpoint doesn't want to receive all the progress details */
754 PJSIP_EVSUB_STATE_TERMINATED);
755
756 if (notification) {
757 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
758 ao2_cleanup(notification);
759 }
760 }
761 } else if (refer->progress) {
762 /* If attended transfer and progress monitoring is being done attach a frame hook so we can monitor it */
763 struct ast_framehook_interface hook = {
765 .event_cb = refer_progress_framehook,
767 .data = refer->progress,
768 .disable_inheritance = 1,
769 };
770
772 if (!refer->progress->transferee) {
774 PJSIP_EVSUB_STATE_TERMINATED);
775
776 ast_log(LOG_WARNING, "Could not copy channel name '%s' during transfer - assuming success\n",
777 ast_channel_name(chan));
778
779 if (notification) {
780 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
781 ao2_cleanup(notification);
782 }
783 }
784 }
785
786 /* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
787 ao2_ref(user_data_wrapper, +1);
788 refer->progress->transfer_data = user_data_wrapper;
789
790 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
791 ao2_ref(refer->progress, +1);
792
793 /* If we can't attach a frame hook for whatever reason send a notification of success immediately */
794 ast_channel_lock(chan);
795 refer->progress->framehook = ast_framehook_attach(chan, &hook);
796 ast_channel_unlock(chan);
797 if (refer->progress->framehook < 0) {
799 PJSIP_EVSUB_STATE_TERMINATED);
800
801 ast_log(LOG_WARNING, "Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
802 ast_channel_name(chan));
803
804 if (notification) {
805 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
806 ao2_cleanup(notification);
807 }
808 }
809
810 ao2_cleanup(refer->progress);
811 }
812
813 /* We need to bump the reference count for the stasis subscription */
814 ao2_ref(refer->progress, +1);
815 /* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
816 * detect if the transfer target has answered the call
817 */
819 if (!refer->progress->bridge_sub) {
821 PJSIP_EVSUB_STATE_TERMINATED);
822
823 ast_log(LOG_WARNING, "Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success\n",
824 ast_channel_name(chan));
825
826 if (notification) {
827 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
828 ao2_cleanup(notification);
829 }
830 }
831
832 ast_channel_lock(chan);
834 ast_channel_unlock(chan);
835
836 ao2_cleanup(refer->progress);
837 } else {
841 }
842 }
843
844 pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL));
845
846 ast_channel_lock(chan);
847 if ((get_xfrdata = pbx_builtin_getvar_helper(chan, "GET_TRANSFERRER_DATA"))) {
848 get_xfrdata = ast_strdupa(get_xfrdata);
849 }
850 ast_channel_unlock(chan);
851 if (!ast_strlen_zero(get_xfrdata)) {
852 const pjsip_msg * msg = refer->rdata->msg_info.msg;
853 const struct pjsip_hdr *end = &msg->hdr;
854 struct pjsip_hdr *hdr = end->next;
855 struct ast_str *pbxvar = ast_str_create(64); /* initial buffer for variable name, extended on demand */
856 char buf[4096]; /* should be enough for one header value */
857 const char *prefix = get_xfrdata;
858
859 /* The '*' alone matches all headers. */
860 if (!strcmp(prefix, "*")) {
861 prefix = "";
862 }
863 if (pbxvar) {
864 for (; hdr != end; hdr = hdr->next) {
865 if (!pj_strnicmp2(&hdr->name, prefix, strlen(prefix))) {
866 const int hdr_name_strlen = pj_strlen(&hdr->name);
867 const int hdr_name_bytes = hdr_name_strlen + 1; /* +1 for string NULL terminator */
868 char hdr_name[hdr_name_bytes];
869 int len;
870 char *value_str;
871
872 ast_copy_pj_str(hdr_name, &hdr->name, hdr_name_bytes);
873 len = pjsip_hdr_print_on(hdr, buf, sizeof(buf) - 1);
874 if (len < 0) {
875 /* ignore too long headers */
876 ast_log(LOG_WARNING, "Could not store header '%s' from transfer on channel '%s' - too long text\n", hdr_name, ast_channel_name(chan));
877 continue;
878 }
879 buf[len] = '\0';
880
881 /* Get value - remove header name (before ':') from buf and trim blanks. */
882 value_str = strchr(buf, ':');
883 if (!value_str) {
884 /* Ignore header without value */
885 continue;
886 }
887 value_str = ast_strip(value_str + 1); /* +1 to get string right after the ':' delimiter (i.e. header value) */
888
889 ast_str_set(&pbxvar, -1, "~HASH~TRANSFER_DATA~%.*s~", hdr_name_strlen, hdr_name);
890 pbx_builtin_setvar_helper(chan, ast_str_buffer(pbxvar), value_str);
891 ast_debug(5, "On channel '%s' set TRANSFER_DATA variable '%s' to value '%s' \n", ast_channel_name(chan), hdr_name, value_str);
892 }
893 }
894 ast_free(pbxvar);
895 } else {
896 ast_log(LOG_ERROR, "Channel '%s' failed to allocate buffer for TRANSFER_DATA variable\n", ast_channel_name(chan));
897 }
898 }
899
900 referred_by = pjsip_msg_find_hdr_by_names(refer->rdata->msg_info.msg,
901 &str_referred_by, &str_referred_by_s, NULL);
902 if (referred_by) {
903 size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
904 char *uri = ast_alloca(uri_size);
905
906 ast_copy_pj_str(uri, &referred_by->hvalue, uri_size);
907 pbx_builtin_setvar_helper(chan, "__SIPREFERREDBYHDR", S_OR(uri, NULL));
908 } else {
909 pbx_builtin_setvar_helper(chan, "SIPREFERREDBYHDR", NULL);
910 }
911
912 if (refer->replaces) {
913 char replaces[512];
914 char *replaces_val = NULL;
915 int len;
916
917 len = pjsip_hdr_print_on(refer->replaces, replaces, sizeof(replaces) - 1);
918 if (len != -1) {
919 /* pjsip_hdr_print_on does not NULL terminate the buffer */
920 replaces[len] = '\0';
921 replaces_val = replaces + sizeof("Replaces:");
922 }
923 pbx_builtin_setvar_helper(chan, "__SIPREPLACESHDR", replaces_val);
924 } else {
925 pbx_builtin_setvar_helper(chan, "SIPREPLACESHDR", NULL);
926 }
927
928 if (refer->refer_to) {
929 char refer_to[PJSIP_MAX_URL_SIZE];
930
931 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->refer_to, refer_to, sizeof(refer_to));
932 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", S_OR(refer_to, NULL));
933 } else {
934 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", NULL);
935 }
936}
937
938/*!
939 * \internal
940 * \brief Set the passed in context variable to the determined transfer context.
941 * \since 13.3.0
942 *
943 * \param context Set to the determined transfer context.
944 * \param session INVITE dialog SIP session.
945 */
946#define DETERMINE_TRANSFER_CONTEXT(context, session) \
947 do { \
948 ast_channel_lock((session)->channel); \
949 context = pbx_builtin_getvar_helper((session)->channel, "TRANSFER_CONTEXT"); \
950 if (ast_strlen_zero(context)) { \
951 context = (session)->endpoint->context; \
952 } else { \
953 context = ast_strdupa(context); \
954 } \
955 ast_channel_unlock((session)->channel); \
956 } while (0) \
957
958struct refer_data {
961 char *from;
962 char *refer_to;
964};
965
966static void refer_data_destroy(void *obj)
967{
968 struct refer_data *rdata = obj;
969
970 ast_free(rdata->destination);
971 ast_free(rdata->from);
972 ast_free(rdata->refer_to);
973
974 ast_refer_destroy(rdata->refer);
975}
976
977static struct refer_data *refer_data_create(const struct ast_refer *refer)
978{
979 char *uri_params;
980 const char *destination;
982
983 if (!rdata) {
984 return NULL;
985 }
986
987 /* typecast to suppress const warning */
988 rdata->refer = ast_refer_ref((struct ast_refer *) refer);
990
991 /* To starts with 'pjsip:' which needs to be removed. */
992 if (!(destination = strchr(destination, ':'))) {
993 goto failure;
994 }
995 ++destination;/* Now skip the ':' */
996
998 if (!rdata->destination) {
999 goto failure;
1000 }
1001
1003 if (!rdata->from) {
1004 goto failure;
1005 }
1006
1008 if (!rdata->refer_to) {
1009 goto failure;
1010 }
1012
1013 /*
1014 * Sometimes from URI can contain URI parameters, so remove them.
1015 *
1016 * sip:user;user-options@domain;uri-parameters
1017 */
1018 uri_params = strchr(rdata->from, '@');
1019 if (uri_params && (uri_params = strchr(uri_params, ';'))) {
1020 *uri_params = '\0';
1021 }
1022 return rdata;
1023
1024failure:
1025 ao2_cleanup(rdata);
1026 return NULL;
1027}
1028
1029/*!
1030 * \internal
1031 * \brief Checks if the given refer var name should be blocked.
1032 *
1033 * \details Some headers are not allowed to be overridden by the user.
1034 * Determine if the given var header name from the user is blocked for
1035 * an outgoing REFER.
1036 *
1037 * \param name name of header to see if it is blocked.
1038 *
1039 * \retval TRUE if the given header is blocked.
1040 */
1041static int is_refer_var_blocked(const char *name)
1042{
1043 int i;
1044
1045 /* Don't block the Max-Forwards header because the user can override it */
1046 static const char *hdr[] = {
1047 "To",
1048 "From",
1049 "Via",
1050 "Route",
1051 "Contact",
1052 "Call-ID",
1053 "CSeq",
1054 "Allow",
1055 "Content-Length",
1056 "Content-Type",
1057 "Request-URI",
1058 };
1059
1060 for (i = 0; i < ARRAY_LEN(hdr); ++i) {
1061 if (!strcasecmp(name, hdr[i])) {
1062 /* Block addition of this header. */
1063 return 1;
1064 }
1065 }
1066 return 0;
1067}
1068
1069/*!
1070 * \internal
1071 * \brief Copies any other refer vars over to the request headers.
1072 *
1073 * \param refer The refer structure to copy headers from
1074 * \param tdata The SIP transmission data
1075 */
1076static enum pjsip_status_code vars_to_headers(const struct ast_refer *refer, pjsip_tx_data *tdata)
1077{
1078 const char *name;
1079 const char *value;
1081
1082 for (iter = ast_refer_var_iterator_init(refer);
1085 if (!is_refer_var_blocked(name)) {
1086 ast_sip_add_header(tdata, name, value);
1087 }
1088 }
1090
1091 return PJSIP_SC_OK;
1092}
1093
1098
1099/*! \brief REFER Out-of-dialog module, used to attach session data structure to subscription */
1100static pjsip_module refer_out_of_dialog_module = {
1101 .name = { "REFER Out-of-dialog Module", 26 },
1102 .id = -1,
1103 .on_tx_request = refer_on_tx_request,
1104 /* Ensure that we are called after res_pjsp_nat module and before transport priority */
1105 .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 4,
1106};
1107
1108/*! \brief Helper function which returns the name-addr of the Refer-To header or NULL */
1109static pjsip_uri *get_refer_to_uri(pjsip_tx_data *tdata)
1110{
1111 const pj_str_t REFER_TO = { "Refer-To", 8 };
1112 pjsip_generic_string_hdr *refer_to;
1113 pjsip_uri *parsed_uri;
1114
1115 if (!(refer_to = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL))
1116 || !(parsed_uri = pjsip_parse_uri(tdata->pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0))
1117 || (!PJSIP_URI_SCHEME_IS_SIP(parsed_uri) && !PJSIP_URI_SCHEME_IS_SIPS(parsed_uri))) {
1118 return NULL;
1119 }
1120
1121 return parsed_uri;
1122}
1123
1124static pj_status_t refer_on_tx_request(pjsip_tx_data *tdata) {
1125 RAII_VAR(struct ast_str *, refer_to_str, ast_str_create(PJSIP_MAX_URL_SIZE), ast_free_ptr);
1126 const pj_str_t REFER_TO = { "Refer-To", 8 };
1127 pjsip_generic_string_hdr *refer_to_hdr;
1128 pjsip_dialog *dlg;
1129 struct refer_data *refer_data;
1130 pjsip_uri *parsed_uri;
1131 pjsip_sip_uri *refer_to_uri;
1132
1133 /*
1134 * If this is a request in response to a 401/407 Unauthorized challenge, the
1135 * Refer-To URI has been rewritten already, so don't attempt to re-write it again.
1136 * Checking for presence of the Authorization header is not an ideal solution. We do this because
1137 * there exists some race condition where this dialog is not the same as the one used
1138 * to send the original request in which case we don't have the correct refer_data.
1139 */
1140 if (!refer_to_str
1141 || pjsip_msg_find_hdr(tdata->msg, PJSIP_H_AUTHORIZATION, NULL)
1142 || !(dlg = pjsip_tdata_get_dlg(tdata))
1143 || !(refer_data = pjsip_dlg_get_mod_data(dlg, refer_out_of_dialog_module.id))
1144 || !refer_data->to_self
1145 || !(parsed_uri = get_refer_to_uri(tdata))) {
1146 goto out;
1147 }
1148 refer_to_uri = pjsip_uri_get_uri(parsed_uri);
1149 ast_sip_rewrite_uri_to_local(refer_to_uri, tdata);
1150
1151 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, parsed_uri, ast_str_buffer(refer_to_str), ast_str_size(refer_to_str));
1152 refer_to_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL);
1153 pj_strdup2(tdata->pool, &refer_to_hdr->hvalue, ast_str_buffer(refer_to_str));
1154
1155out:
1156 return PJ_SUCCESS;
1157}
1158
1159static int refer_unreference_dialog(void *obj)
1160{
1161 struct refer_out_of_dialog *data = obj;
1162
1163 /* This is why we keep the dialog on the subscription. When the subscription
1164 * is destroyed, there is no guarantee that the underlying dialog is ready
1165 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1166 * either. The dialog could be destroyed before our subscription is. We fix
1167 * this problem by keeping a reference to the dialog until it is time to
1168 * destroy the subscription.
1169 */
1170 pjsip_dlg_dec_session(data->dlg, &refer_out_of_dialog_module);
1171 data->dlg = NULL;
1172
1173 return 0;
1174}
1175/*! \brief Destructor for REFER out of dialog structure */
1176static void refer_out_of_dialog_destroy(void *obj) {
1177 struct refer_out_of_dialog *data = obj;
1178
1179 if (data->dlg) {
1180 /* ast_sip_push_task_wait_servant should not be called in a destructor,
1181 * however in this case it seems to be fine.
1182 */
1184 }
1185}
1186
1187/*!
1188 * \internal
1189 * \brief Callback function to report status of implicit REFER-NOTIFY subscription.
1190 *
1191 * This function will be called on any state change in the REFER-NOTIFY subscription.
1192 * Its primary purpose is to report SUCCESS/FAILURE of a refer initiated via
1193 * \ref refer_send as well as to terminate the subscription, if necessary.
1194 */
1195static void refer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
1196{
1197 pjsip_tx_data *tdata;
1198 RAII_VAR(struct ast_sip_endpoint *, endpt, NULL, ao2_cleanup);
1200 int refer_success;
1201 int res = 0;
1202
1203 if (!event) {
1204 return;
1205 }
1206
1207 refer_data = pjsip_evsub_get_mod_data(sub, refer_out_of_dialog_module.id);
1208 if (!refer_data || !refer_data->dlg) {
1209 return;
1210 }
1211
1213
1214 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
1215 /* Check if subscription is suppressed and terminate and send completion code, if so. */
1216 pjsip_rx_data *rdata;
1217 pjsip_generic_string_hdr *refer_sub;
1218 const pj_str_t REFER_SUB = { "Refer-Sub", 9 };
1219
1220 ast_debug(3, "Refer accepted by %s\n", endpt ? ast_sorcery_object_get_id(endpt) : "(unknown endpoint)");
1221
1222 /* Check if response message */
1223 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1224 rdata = event->body.tsx_state.src.rdata;
1225
1226 /* Find Refer-Sub header */
1227 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &REFER_SUB, NULL);
1228
1229 /* Check if subscription is suppressed. If it is, the far end will not terminate it,
1230 * and the subscription will remain active until it times out. Terminating it here
1231 * eliminates the unnecessary timeout.
1232 */
1233 if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
1234 /* Since no subscription is desired, assume that call has been referred successfully
1235 * and terminate subscription.
1236 */
1237 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1238 pjsip_evsub_terminate(sub, PJ_TRUE);
1239 res = -1;
1240 }
1241 }
1242 } else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
1243 pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
1244 /* Check for NOTIFY complete or error. */
1245 pjsip_msg *msg;
1246 pjsip_msg_body *body;
1247 pjsip_status_line status_line = { .code = 0 };
1248 pj_bool_t is_last;
1249 pj_status_t status;
1250
1251 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1252 pjsip_rx_data *rdata;
1253 pj_str_t refer_str;
1254 pj_cstr(&refer_str, "REFER");
1255
1256 rdata = event->body.tsx_state.src.rdata;
1257 msg = rdata->msg_info.msg;
1258
1259 if (msg->type == PJSIP_RESPONSE_MSG
1260 && (event->body.tsx_state.tsx->status_code == 401
1261 || event->body.tsx_state.tsx->status_code == 407)
1262 && pj_stristr(&refer_str, &event->body.tsx_state.tsx->method.name)
1263 && ++refer_data->authentication_challenge_count < MAX_RX_CHALLENGES
1264 && endpt) {
1265
1266 if (!ast_sip_create_request_with_auth(&endpt->outbound_auths,
1267 event->body.tsx_state.src.rdata, event->body.tsx_state.tsx->last_tx, &tdata)) {
1268 /* Send authed REFER */
1270 goto out;
1271 }
1272 }
1273
1274 if (msg->type == PJSIP_REQUEST_MSG) {
1275 if (!pjsip_method_cmp(&msg->line.req.method, pjsip_get_notify_method())) {
1276 body = msg->body;
1277 if (body && !pj_stricmp2(&body->content_type.type, "message")
1278 && !pj_stricmp2(&body->content_type.subtype, "sipfrag")) {
1279 pjsip_parse_status_line((char *)body->data, body->len, &status_line);
1280 }
1281 }
1282 } else {
1283 status_line.code = msg->line.status.code;
1284 status_line.reason = msg->line.status.reason;
1285 }
1286 } else {
1287 status_line.code = 500;
1288 status_line.reason = *pjsip_get_status_text(500);
1289 }
1290
1291 is_last = (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED);
1292 /* If the status code is >= 200, the subscription is finished. */
1293 if (status_line.code >= 200 || is_last) {
1294 res = -1;
1295
1296 refer_success = status_line.code >= 200 && status_line.code < 300;
1297
1298 /* If subscription not terminated and subscription is finished (status code >= 200)
1299 * terminate it */
1300 if (!is_last) {
1301 pjsip_tx_data *tdata;
1302
1303 status = pjsip_evsub_initiate(sub, pjsip_get_subscribe_method(), 0, &tdata);
1304 if (status == PJ_SUCCESS) {
1305 pjsip_evsub_send_request(sub, tdata);
1306 }
1307 }
1308 ast_debug(3, "Refer completed: %d %.*s (%s)\n",
1309 status_line.code,
1310 (int)status_line.reason.slen, status_line.reason.ptr,
1311 refer_success ? "Success" : "Failure");
1312 }
1313 }
1314
1315out:
1316 if (res) {
1318 }
1319}
1320
1321/*!
1322 * \internal
1323 * \brief Send a REFER
1324 *
1325 * \param data The outbound refer data structure
1326 *
1327 * \return 0: success, -1: failure
1328 */
1329static int refer_send(void *data)
1330{
1331 struct refer_data *rdata = data; /* The caller holds a reference */
1332 pjsip_tx_data *tdata;
1333 pjsip_evsub *sub;
1334 pj_str_t tmp;
1335 char refer_to_str[PJSIP_MAX_URL_SIZE];
1336 char disp_name_escaped[128];
1337 struct refer_out_of_dialog *refer;
1338 struct pjsip_evsub_user xfer_cb;
1339 RAII_VAR(char *, uri, NULL, ast_free);
1340 RAII_VAR(char *, tmp_str, NULL, ast_free);
1341 RAII_VAR(char *, display_name, NULL, ast_free);
1342 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1343 RAII_VAR(struct ast_sip_endpoint *, refer_to_endpoint, NULL, ao2_cleanup);
1344
1345 endpoint = ast_sip_get_endpoint(rdata->destination, 1, &uri);
1346 if (!endpoint) {
1348 "PJSIP REFER - Could not find endpoint '%s' and no default outbound endpoint configured\n",
1349 rdata->destination);
1350 return -1;
1351 }
1352 ast_debug(3, "Request URI: %s\n", uri);
1353
1354 refer_to_endpoint = ast_sip_get_endpoint(rdata->refer_to, 0, &tmp_str);
1355 if (!tmp_str) {
1356 ast_log(LOG_WARNING, "PJSIP REFER - Refer to not a valid resource identifier or SIP URI\n");
1357 return -1;
1358 }
1359 if (!(refer = ao2_alloc(sizeof(struct refer_out_of_dialog), refer_out_of_dialog_destroy))) {
1360 ast_log(LOG_ERROR, "PJSIP REFER - Could not allocate resources.\n");
1361 return -1;
1362 }
1363 /* The dialog will be terminated in the subscription event callback
1364 * when the subscription has terminated. */
1366 refer->dlg = ast_sip_create_dialog_uac(endpoint, uri, NULL);
1367 if (!refer->dlg) {
1368 ast_log(LOG_WARNING, "PJSIP REFER - Could not create dialog\n");
1369 ao2_cleanup(refer);
1370 return -1;
1371 }
1372 ast_sip_dialog_set_endpoint(refer->dlg, endpoint);
1373
1374 pj_bzero(&xfer_cb, sizeof(xfer_cb));
1375 xfer_cb.on_evsub_state = &refer_client_on_evsub_state;
1376 if (pjsip_xfer_create_uac(refer->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
1377 ast_log(LOG_WARNING, "PJSIP REFER - Could not create uac\n");
1378 ao2_cleanup(refer);
1379 return -1;
1380 }
1381
1382 display_name = ast_refer_get_var_and_unlink(rdata->refer, "display_name");
1383 if (display_name) {
1384 ast_escape_quoted(display_name, disp_name_escaped, sizeof(disp_name_escaped));
1385 snprintf(refer_to_str, sizeof(refer_to_str), "\"%s\" <%s>", disp_name_escaped, tmp_str);
1386 } else {
1387 snprintf(refer_to_str, sizeof(refer_to_str), "%s", tmp_str);
1388 }
1389
1390 /* refer_out_of_dialog_module requires a reference to dlg
1391 * which will be released in refer_client_on_evsub_state()
1392 * when the implicit REFER subscription terminates */
1393 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, refer);
1394 if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, refer_to_str), &tdata) != PJ_SUCCESS) {
1395 ast_log(LOG_WARNING, "PJSIP REFER - Could not create request\n");
1396 goto failure;
1397 }
1398
1399 if (refer_to_endpoint && rdata->to_self) {
1400 pjsip_dlg_add_usage(refer->dlg, &refer_out_of_dialog_module, rdata);
1401 }
1402
1403 ast_sip_update_to_uri(tdata, uri);
1404 ast_sip_update_from(tdata, rdata->from);
1405
1406 /*
1407 * This copies any headers found in the refer's variables to
1408 * tdata.
1409 */
1410 vars_to_headers(rdata->refer, tdata);
1411 ast_debug(1, "Sending REFER to '%s' (via endpoint %s) from '%s'\n",
1412 rdata->destination, ast_sorcery_object_get_id(endpoint), rdata->from);
1413
1414 if (pjsip_xfer_send_request(sub, tdata) == PJ_SUCCESS) {
1415 return 0;
1416 }
1417
1418failure:
1419 ao2_cleanup(refer);
1420 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1421 pjsip_evsub_terminate(sub, PJ_FALSE);
1422 return -1;
1423}
1424
1425static int sip_refer_send(const struct ast_refer *refer)
1426{
1427 struct refer_data *rdata;
1428 int res;
1429
1431 ast_log(LOG_ERROR, "SIP REFER - a 'To' URI must be specified\n");
1432 return -1;
1433 }
1434
1435 rdata = refer_data_create(refer);
1436 if (!rdata) {
1437 return -1;
1438 }
1439
1441 ao2_ref(rdata, -1);
1442
1443 return res;
1444}
1445
1446static const struct ast_refer_tech refer_tech = {
1447 .name = "pjsip",
1448 .refer_send = sip_refer_send,
1449};
1450
1451static char *copy_string(struct pj_str_t *str)
1452{
1453 int len = pj_strlen(str) + 1;
1454 char *dst = ast_malloc(len);
1455 if (!dst) {
1456 return NULL;
1457 }
1458 ast_copy_pj_str(dst, str, len);
1459 return dst;
1460}
1461
1462static int add_refer_param(struct ast_refer_params *params, const char *key, struct pj_str_t *str)
1463{
1464 struct ast_refer_param param;
1465
1466 param.param_name = ast_strdup(key);
1467 if (!param.param_name) {
1468 return 0;
1469 }
1470
1471 param.param_value = copy_string(str);
1472 if (!param.param_value) {
1473 ast_free((char *) param.param_name);
1474 return 0;
1475 }
1476
1477 if (AST_VECTOR_APPEND(params, param) != 0) {
1478 ast_free((char *) param.param_name);
1479 ast_free((char *) param.param_value);
1480 return 0;
1481 }
1482 return 1;
1483}
1484
1485
1486static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
1487 pjsip_param *replaces_param, struct refer_progress *progress)
1488{
1489 int parsed_len;
1490 pjsip_replaces_hdr *replaces;
1491 pjsip_generic_string_hdr *referred_hdr;
1492
1493
1495
1496 struct ast_framehook_interface hook = {
1498 .event_cb = refer_ari_progress_framehook,
1500 .data = progress,
1501 .disable_inheritance = 1,
1502 };
1503
1504 static const pj_str_t str_referred_by = { "Referred-By", 11 };
1505 static const pj_str_t str_referred_by_s = { "b", 1 };
1506 static const pj_str_t str_replaces = { "Replaces", 8 };
1507
1508
1510 if (!state) {
1511 return 500;
1512 }
1513
1514 state->last_response = AST_TRANSFER_INVALID;
1515
1516 state->params = ao2_alloc(sizeof(struct ast_refer_params), refer_params_destroy);
1517 if (!state->params) {
1518 return 500;
1519 }
1520 AST_VECTOR_INIT(state->params, 0);
1521
1522
1523 ast_channel_ref(session->channel);
1524 state->transferer_chan = session->channel;
1525
1526 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1527 ast_copy_pj_str(state->exten, &target->user, sizeof(state->exten));
1528
1529 /*
1530 * We may want to match in the dialplan without any user
1531 * options getting in the way.
1532 */
1534
1535 referred_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg,
1536 &str_referred_by, &str_referred_by_s, NULL);
1537 if (referred_hdr) {
1538 state->referred_by = copy_string(&referred_hdr->hvalue);
1539 if (!state->referred_by) {
1540 return 500;
1541 }
1542 }
1543
1544 if (replaces_param) {
1545 pjsip_dialog *dlg;
1546 pj_str_t replaces_content = { 0, };
1547 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1548
1549 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1550 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1551 pj_strlen(&replaces_content), &parsed_len))) {
1552 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1554 return 400;
1555 }
1556
1557 dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE);
1558 if (dlg) {
1559 state->other_session = ast_sip_dialog_get_session(dlg);
1560 pjsip_dlg_dec_lock(dlg);
1561 }
1562
1563 state->protocol_id = copy_string(&replaces->call_id);
1564 if (!state->protocol_id) {
1565 return 500;
1566 }
1567
1568 if (!add_refer_param(state->params, "from", &replaces->from_tag)) {
1569 return 500;
1570 }
1571
1572 if (!add_refer_param(state->params, "to", &replaces->to_tag)) {
1573 return 500;
1574 }
1575 }
1576
1577 ao2_ref(session, +1);
1578 state->transferer = session;
1579
1580
1581 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
1582 ao2_ref(progress, +1);
1583 ast_channel_lock(session->channel);
1584 progress->framehook = ast_framehook_attach(session->channel, &hook);
1585 ast_channel_unlock(session->channel);
1586
1587 if (progress->framehook < 0) {
1589 return 500;
1590 }
1591
1592 if (ari_notify(state)) {
1593 ast_channel_lock(session->channel);
1594 ast_framehook_detach(session->channel, progress->framehook);
1595 progress->framehook = -1;
1597 ast_channel_unlock(session->channel);
1598 return 500;
1599 }
1600
1601 /* Transfer ownership to the progress */
1602 progress->ari_state = state;
1603 state = NULL;
1604 return 200;
1605}
1606
1607static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri,
1608 pjsip_param *replaces_param, struct refer_progress *progress)
1609{
1610 const pj_str_t str_replaces = { "Replaces", 8 };
1611 pj_str_t replaces_content;
1612 pjsip_replaces_hdr *replaces;
1613 int parsed_len;
1614 pjsip_dialog *dlg;
1615
1616 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1617
1618 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1619 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1620 pj_strlen(&replaces_content), &parsed_len))) {
1621 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1623 return 400;
1624 }
1625
1626 /* See if the dialog is local, or remote */
1627 if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
1628 RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
1629 struct refer_attended *attended;
1630
1631 pjsip_dlg_dec_lock(dlg);
1632
1633 if (!other_session) {
1634 ast_debug(3, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it\n",
1636 return 603;
1637 }
1638
1639 /* We defer actually doing the attended transfer to the other session so no deadlock can occur */
1640 if (!(attended = refer_attended_alloc(session, other_session, progress))) {
1641 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",
1643 return 500;
1644 }
1645
1647 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not defer termination, rejecting\n",
1649 ao2_cleanup(attended);
1650 return 500;
1651 }
1652
1653 /* Push it to the other session, which will have both channels with minimal locking */
1654 if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {
1657 ao2_cleanup(attended);
1658 return 500;
1659 }
1660
1661 ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
1662 ast_channel_name(session->channel));
1663
1664 return 200;
1665 } else {
1666 const char *context;
1667 struct refer_blind refer = { 0, };
1668 int response;
1669
1671
1672 if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
1673 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",
1675 return 404;
1676 }
1677
1678 refer.context = context;
1679 refer.progress = progress;
1680 refer.rdata = rdata;
1681 refer.replaces = replaces;
1682 refer.refer_to = target_uri;
1683 refer.attended = 1;
1684
1686 ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting\n",
1687 ast_channel_name(session->channel),
1689 return 500;
1690 }
1691
1693 "external_replaces", context, refer_blind_callback, &refer));
1694
1696 if (response != 200) {
1698 }
1699
1700 return response;
1701 }
1702}
1703
1704static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
1705 struct refer_progress *progress)
1706{
1707 const char *context;
1708 char exten[AST_MAX_EXTENSION];
1709 struct refer_blind refer = { 0, };
1710 int response;
1711
1712 /* If no explicit transfer context has been provided use their configured context */
1714
1715 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1716 ast_copy_pj_str(exten, &target->user, sizeof(exten));
1717
1718 /*
1719 * We may want to match in the dialplan without any user
1720 * options getting in the way.
1721 */
1723
1724 /* Uri without exten */
1725 if (ast_strlen_zero(exten)) {
1726 ast_copy_string(exten, "s", sizeof(exten));
1727 ast_debug(3, "Channel '%s' from endpoint '%s' attempted blind transfer to a target without extension. Target was set to 's@%s'\n",
1729 }
1730
1731 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
1732 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
1733 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context);
1734 return 404;
1735 }
1736
1737 refer.context = context;
1738 refer.progress = progress;
1739 refer.rdata = rdata;
1740 refer.refer_to = target;
1741 refer.attended = 0;
1742
1744 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer but could not defer termination, rejecting\n",
1745 ast_channel_name(session->channel),
1747 return 500;
1748 }
1749
1751 exten, context, refer_blind_callback, &refer));
1752
1754 if (response != 200) {
1756 }
1757
1758 return response;
1759}
1760
1761/*! \brief Structure used to retrieve channel from another session */
1763 /*! \brief Session we want the channel from */
1765 /*! \brief Channel from the session (with reference) */
1767 /*! \brief Bridge the channel is in */
1769};
1770
1771/*! \brief Task for invite replaces */
1772static int invite_replaces(void *data)
1773{
1774 struct invite_replaces *invite = data;
1775
1776 if (!invite->session->channel) {
1777 return -1;
1778 }
1779
1781 invite->channel = invite->session->channel;
1782
1784 return 0;
1785}
1786
1787static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1788{
1789 pjsip_dialog *other_dlg = NULL;
1790 pjsip_tx_data *packet;
1791 int response = 0;
1792 RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup);
1793 struct invite_replaces invite;
1794
1795 /* If a Replaces header is present make sure it is valid */
1796 if (pjsip_replaces_verify_request(rdata, &other_dlg, PJ_TRUE, &packet) != PJ_SUCCESS) {
1797 response = packet->msg->line.status.code;
1798 ast_assert(response != 0);
1799 pjsip_tx_data_dec_ref(packet);
1800 goto inv_replace_failed;
1801 }
1802
1803 /* If no other dialog exists then this INVITE request does not have a Replaces header */
1804 if (!other_dlg) {
1805 return 0;
1806 }
1807
1808 other_session = ast_sip_dialog_get_session(other_dlg);
1809 pjsip_dlg_dec_lock(other_dlg);
1810
1811 /* Don't accept an in-dialog INVITE with Replaces as it does not make much sense */
1812 if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
1813 response = 488;
1814 goto inv_replace_failed;
1815 }
1816
1817 if (!other_session) {
1818 ast_debug(3, "INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist\n",
1820 response = 481;
1821 goto inv_replace_failed;
1822 }
1823
1824 invite.session = other_session;
1825
1826 if (ast_sip_push_task_wait_serializer(other_session->serializer, invite_replaces,
1827 &invite)) {
1828 response = 481;
1829 goto inv_replace_failed;
1830 }
1831
1832 ast_channel_lock(session->channel);
1834 ast_channel_unlock(session->channel);
1835 ast_raw_answer(session->channel);
1836
1837 ast_debug(3, "INVITE with Replaces being attempted. '%s' --> '%s'\n",
1839
1840 /* Unhold the channel now, as later we are not having access to it anymore */
1841 ast_queue_unhold(session->channel);
1843
1844 if (!invite.bridge) {
1845 struct ast_channel *chan = session->channel;
1846
1847 /*
1848 * This will use a synchronous task but we aren't operating in
1849 * the serializer at this point in time, so it won't deadlock.
1850 */
1851 if (!ast_channel_move(invite.channel, chan)) {
1852 /*
1853 * We can't directly use session->channel because ast_channel_move()
1854 * does a masquerade which changes session->channel to a different
1855 * channel. To ensure we work on the right channel we store a
1856 * pointer locally before we begin so it remains valid.
1857 */
1858 ast_hangup(chan);
1859 } else {
1860 response = AST_CAUSE_FAILURE;
1861 }
1862 } else {
1863 if (ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL,
1865 response = AST_CAUSE_FAILURE;
1866 }
1867 }
1868
1869 ast_channel_unref(invite.channel);
1870 ao2_cleanup(invite.bridge);
1871
1872 if (!response) {
1873 /*
1874 * On success we cannot use session->channel in the debug message.
1875 * This thread either no longer has a ref to session->channel or
1876 * session->channel is no longer the original channel.
1877 */
1878 ast_debug(3, "INVITE with Replaces successfully completed.\n");
1879 } else {
1880 ast_debug(3, "INVITE with Replaces failed on channel '%s', hanging up with cause '%d'\n",
1881 ast_channel_name(session->channel), response);
1882 ast_channel_lock(session->channel);
1883 ast_channel_hangupcause_set(session->channel, response);
1884 ast_channel_unlock(session->channel);
1885 ast_hangup(session->channel);
1886 }
1887
1888 return 1;
1889
1890inv_replace_failed:
1891 if (session->inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
1892 ast_debug(3, "INVITE with Replaces failed on channel '%s', sending response of '%d'\n",
1893 ast_channel_name(session->channel), response);
1894 session->defer_terminate = 1;
1895 ast_hangup(session->channel);
1896
1897 if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS
1898 && packet) {
1900 }
1901 } else {
1902 ast_debug(3, "INVITE with Replaces in-dialog on channel '%s', hanging up\n",
1903 ast_channel_name(session->channel));
1904 ast_queue_hangup(session->channel);
1905 }
1906
1907 return 1;
1908}
1909
1910static int refer_incoming_refer_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1911{
1912 pjsip_generic_string_hdr *refer_to;
1913 char *uri;
1914 size_t uri_size;
1915 pjsip_uri *target;
1916 pjsip_sip_uri *target_uri;
1918 pjsip_param *replaces;
1919 int response;
1920
1921 static const pj_str_t str_refer_to = { "Refer-To", 8 };
1922 static const pj_str_t str_refer_to_s = { "r", 1 };
1923 static const pj_str_t str_replaces = { "Replaces", 8 };
1924
1925 if (!session->channel) {
1926 /* No channel to refer. Likely because the call was just hung up. */
1927 pjsip_dlg_respond(session->inv_session->dlg, rdata, 404, NULL, NULL, NULL);
1928 ast_debug(3, "Received a REFER on a session with no channel from endpoint '%s'.\n",
1930 return 0;
1931 }
1932
1933 if (!session->endpoint->allowtransfer) {
1934 pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
1935 ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
1937 return 0;
1938 }
1939
1940 /* A Refer-To header is required */
1941 refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL);
1942 if (!refer_to) {
1943 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1944 ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
1946 return 0;
1947 }
1948
1949 /* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri
1950 * as pjsip_parse_uri require a NULL terminated uri
1951 */
1952
1953 uri_size = pj_strlen(&refer_to->hvalue) + 1;
1954 uri = ast_alloca(uri_size);
1955 ast_copy_pj_str(uri, &refer_to->hvalue, uri_size);
1956
1957 target = pjsip_parse_uri(rdata->tp_info.pool, uri, uri_size - 1, 0);
1958
1959 if (!target
1960 || (!PJSIP_URI_SCHEME_IS_SIP(target)
1961 && !PJSIP_URI_SCHEME_IS_SIPS(target))) {
1962
1963 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1964 ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n",
1965 uri, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
1966 return 0;
1967 }
1968 target_uri = pjsip_uri_get_uri(target);
1969
1970 /* Set up REFER progress subscription if requested/possible */
1971 if (refer_progress_alloc(session, rdata, &progress)) {
1972 pjsip_dlg_respond(session->inv_session->dlg, rdata, 500, NULL, NULL, NULL);
1973 ast_debug(3, "Could not set up subscription for REFER on channel '%s' from endpoint '%s'\n",
1975 return 0;
1976 }
1977
1978 replaces = pjsip_param_find(&target_uri->header_param, &str_replaces);
1979 if (!replaces) {
1980 replaces = pjsip_param_find(&target_uri->other_param, &str_replaces);
1981 }
1982
1983 /* Determine if this is handled externally or an attended or blind transfer */
1984 if (session->transferhandling_ari) {
1985 response = refer_incoming_ari_request(session, rdata, target_uri, replaces, progress);
1986 } else if (replaces) {
1987 response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
1988 } else {
1989 response = refer_incoming_blind_request(session, rdata, target_uri, progress);
1990 }
1991
1992 if (!progress) {
1993 /* The transferer has requested no subscription, so send a final response immediately */
1994 pjsip_tx_data *tdata;
1995 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
1996 const pj_str_t str_false = { "false", 5 };
1997 pjsip_hdr *hdr;
1998
1999 ast_debug(3, "Progress monitoring not requested for REFER on channel '%s' from endpoint '%s', sending immediate response of '%d'\n",
2000 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), response);
2001
2002 if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, response, NULL, &tdata) != PJ_SUCCESS) {
2003 pjsip_dlg_respond(session->inv_session->dlg, rdata, response, NULL, NULL, NULL);
2004 return 0;
2005 }
2006
2007 hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
2008 pjsip_msg_add_hdr(tdata->msg, hdr);
2009
2010 pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2011 } else if (response != 200) {
2012 /* Since this failed we can send a final NOTIFY now and terminate the subscription */
2013 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
2014
2015 if (notification) {
2016 /* The refer_progress_notify function will call ao2_cleanup on this for us */
2017 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
2018 ao2_cleanup(notification);
2019 }
2020 }
2021 }
2022
2023 return 0;
2024}
2025
2026static int refer_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
2027{
2028 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
2030 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_invite_method)) {
2032 } else {
2033 return 0;
2034 }
2035}
2036
2037/*!
2038 * \brief Use the value of a channel variable as the value of a SIP header
2039 *
2040 * This looks up a variable name on a channel, then takes that value and adds
2041 * it to an outgoing SIP request. If the header already exists on the message,
2042 * then no action is taken.
2043 *
2044 * \pre chan is locked.
2045 *
2046 * \param chan The channel on which to find the variable.
2047 * \param var_name The name of the channel variable to use.
2048 * \param header_name The name of the SIP header to add to the outgoing message.
2049 * \param tdata The outgoing SIP message on which to add the header
2050 */
2051static void add_header_from_channel_var(struct ast_channel *chan, const char *var_name, const char *header_name, pjsip_tx_data *tdata)
2052{
2053 const char *var_value;
2054 pj_str_t pj_header_name;
2055 pjsip_hdr *header;
2056
2057 var_value = pbx_builtin_getvar_helper(chan, var_name);
2058 if (ast_strlen_zero(var_value)) {
2059 return;
2060 }
2061
2062 pj_cstr(&pj_header_name, header_name);
2063 header = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_header_name, NULL);
2064 if (header) {
2065 return;
2066 }
2067 ast_sip_add_header(tdata, header_name, var_value);
2068}
2069
2070static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
2071{
2072 if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method)
2073 || !session->channel
2074 || session->inv_session->state != PJSIP_INV_STATE_NULL) {
2075 return;
2076 }
2077
2078 ast_channel_lock(session->channel);
2079 add_header_from_channel_var(session->channel, "SIPREPLACESHDR", "Replaces", tdata);
2080 add_header_from_channel_var(session->channel, "SIPREFERREDBYHDR", "Referred-By", tdata);
2081 ast_channel_unlock(session->channel);
2082}
2083
2086 .incoming_request = refer_incoming_request,
2087 .outgoing_request = refer_outgoing_request,
2088};
2089
2090static int load_module(void)
2091{
2092 const pj_str_t str_norefersub = { "norefersub", 10 };
2093
2094 pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint());
2095 pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint());
2096
2097 if (ast_sip_get_norefersub()) {
2098 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub);
2099 }
2100
2103 }
2104
2106 if (!refer_serializer) {
2109 }
2110
2114
2116
2118}
2119
2129
2130AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Blind and Attended Transfer Support",
2131 .support_level = AST_MODULE_SUPPORT_CORE,
2132 .load = load_module,
2133 .unload = unload_module,
2134 .load_pri = AST_MODPRI_APP_DEPEND,
2135 .requires = "res_pjsip,res_pjsip_session,res_pjsip_pubsub",
jack_status_t status
Definition app_jack.c:149
const char * str
Definition app_jack.c:150
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_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#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:1947
struct ast_bridge * ast_bridge_transfer_acquire_bridge(struct ast_channel *chan)
Acquire the channel's bridge for transfer purposes.
Definition bridge.c:4487
ast_transfer_type
Definition bridge.h:1113
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:4504
ast_transfer_result
Definition bridge.h:1102
@ AST_BRIDGE_TRANSFER_NOT_PERMITTED
Definition bridge.h:1106
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition bridge.h:1104
@ AST_BRIDGE_TRANSFER_INVALID
Definition bridge.h:1108
@ AST_BRIDGE_TRANSFER_FAIL
Definition bridge.h:1110
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition bridge.h:594
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
Definition bridge.c:4756
Internal Asterisk hangup causes.
#define AST_CAUSE_FAILURE
Definition causes.h:150
const char * ast_channel_name(const struct ast_channel *chan)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2538
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition channel.c:1181
#define ast_channel_lock(chan)
Definition channel.h:2982
#define ast_channel_ref(c)
Increase channel reference count.
Definition channel.h:3007
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:1170
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:10714
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1416
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition channel.c:1273
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3018
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition channel.h:3029
#define ast_channel_unlock(chan)
Definition channel.h:2983
#define AST_MAX_EXTENSION
Definition channel.h:134
int ast_raw_answer(struct ast_channel *chan)
Answer a channel.
Definition channel.c:2688
@ AST_STATE_RING
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition channel.c:7398
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.
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2094
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition res_pjsip.c:2088
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.
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Definition res_pjsip.h:2189
int ast_sip_thread_is_servant(void)
Determine if the current thread is a SIP servant thread.
Definition res_pjsip.c:2281
#define ast_sip_push_task_wait_servant(serializer, sip_task, task_data)
Definition res_pjsip.h:2133
static char prefix[MAX_PREFIX]
Definition http.c:144
@ AST_TRANSFER_FAILED
@ AST_TRANSFER_UNAVAILABLE
@ AST_TRANSFER_SUCCESS
@ AST_TRANSFER_PROGRESS
@ AST_TRANSFER_INVALID
@ AST_FRAME_CONTROL
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_PROCEEDING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ AST_CONTROL_TRANSFER
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:331
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition module.h:478
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_APP_DEPEND
Definition module.h:342
@ 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:4196
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:372
int ast_refer_tech_unregister(const struct ast_refer_tech *tech)
Unregister a refer technology.
Definition refer.c:492
const char * ast_refer_get_to(const struct ast_refer *refer)
Retrieve the destination of this refer.
Definition refer.c:231
int ast_refer_var_iterator_next(struct ast_refer_var_iterator *iter, const char **name, const char **value)
Get the next variable name and value.
Definition refer.c:351
struct ast_refer_var_iterator * ast_refer_var_iterator_init(const struct ast_refer *refer)
Create a new refer variable iterator.
Definition refer.c:337
const char * ast_refer_get_from(const struct ast_refer *refer)
Retrieve the source of this refer.
Definition refer.c:226
char * ast_refer_get_var_and_unlink(struct ast_refer *refer, const char *name)
Get the specified variable on the refer and unlink it from the container of variables.
Definition refer.c:269
struct ast_refer * ast_refer_destroy(struct ast_refer *refer)
Destroy an ast_refer.
Definition refer.c:154
int ast_refer_notify_transfer_request(struct ast_channel *originating_chan, const char *referred_by, const char *exten, const char *protocol_id, struct ast_channel *dest, struct ast_refer_params *params, enum ast_control_transfer state)
Notify a transfer request.
Definition refer.c:541
const char * ast_refer_get_refer_to(const struct ast_refer *refer)
Get the "refer-to" value of a refer.
Definition refer.c:221
int ast_refer_tech_register(const struct ast_refer_tech *tech)
Register a refer technology.
Definition refer.c:448
struct ast_refer * ast_refer_ref(struct ast_refer *refer)
Bump a refer's ref count.
Definition refer.c:148
int ast_refer_get_to_self(const struct ast_refer *refer)
Retrieve the "to_self" value of this refer.
Definition refer.c:236
void ast_refer_var_iterator_destroy(struct ast_refer_var_iterator *iter)
Destroy a refer variable iterator.
Definition refer.c:378
static struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
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:3220
unsigned int ast_sip_get_norefersub(void)
Retrieve the global setting 'norefersub'.
void ast_sip_unregister_service(pjsip_module *module)
Definition res_pjsip.c:127
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition res_pjsip.c:111
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:958
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:599
int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, pjsip_tx_data *tdata, pjsip_tx_data **new_request)
Create a response to an authentication challenge.
Definition res_pjsip.c:208
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:514
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition res_pjsip.h:3529
int ast_sip_update_from(pjsip_tx_data *tdata, char *from)
Overwrite fields in the outbound 'From' header.
Definition res_pjsip.c:3354
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition res_pjsip.h:3364
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:2172
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:1973
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:3294
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:2002
#define MAX_RX_CHALLENGES
Definition res_pjsip.h:108
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 int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target, pjsip_param *replaces_param, struct refer_progress *progress)
static 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 char * copy_string(struct pj_str_t *str)
static void refer_attended_destroy(void *obj)
Destructor for attended transfer task.
static int sip_refer_send(const struct ast_refer *refer)
static void transfer_ari_state_destroy(void *obj)
Destructor of the state used for the ARI transfer.
static int 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_params_destroy(void *obj)
static void refer_progress_destroy(void *obj)
Destructor for REFER progress sutrcture.
static int ari_notify(struct transfer_ari_state *state)
static int refer_send(void *data)
static int defer_termination_cancel_task(void *data)
static struct ast_frame * refer_ari_progress_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
Progress monitoring frame hook - examines frames to determine state of transfer. Used for the ari-onl...
static 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 int add_refer_param(struct ast_refer_params *params, const char *key, struct pj_str_t *str)
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.
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:2381
@ 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:1090
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:1144
#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:1241
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition stasis.c:1038
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
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
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
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 attribute_pure ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition strings.h:742
Blob of data associated with a bridge.
struct ast_channel_snapshot * channel
Structure that contains information about a bridge.
Definition bridge.h:353
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
enum ast_frame_type frametype
union ast_frame::@239 data
struct ast_module * self
Definition module.h:356
const char * param_value
Definition refer.h:83
const char * param_name
Definition refer.h:82
A refer technology.
Definition refer.h:57
const char *const name
Name of this refer technology.
Definition refer.h:66
struct ao2_iterator iter
Definition refer.c:333
A refer.
Definition refer.c:59
An entity with which Asterisk communicates.
Definition res_pjsip.h:1061
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.
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.
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.
struct ast_refer * refer
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.
struct transfer_ari_state * ari_state
State related to the transfer in ARI only mode.
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.
struct ast_sip_session * transferer
A deferred session used by the ARI only mode.
struct ast_sip_session * other_session
char exten[AST_MAX_EXTENSION]
struct ast_channel * transferer_chan
struct ast_refer_params * params
AO2 object that wraps data for transfer_channel_cb.
Definition bridge.h:1123
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).
FILE * out
Definition utils/frame.c:33
int error(const char *format,...)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
Definition utils.c:817
#define ARRAY_LEN(a)
Definition utils.h:706
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691