Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 if (ari_state->transferer && notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
236 /* Gave the ref to the pushed task. */
237 ari_state->transferer = NULL;
238 }
239 }
240 ari_notify(ari_state);
241 }
242
243 pjsip_dlg_dec_lock(notification->progress->dlg);
244
245 return 0;
246}
247
248static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
249 struct stasis_message *message)
250{
251 struct refer_progress *progress = data;
252 struct ast_bridge_blob *enter_blob;
253 struct refer_progress_notification *notification;
254 struct ast_channel *chan;
255
257 ao2_ref(progress, -1);
258 return;
259 }
260
262 /* Don't care */
263 return;
264 }
265
266 enter_blob = stasis_message_data(message);
267 if (strcmp(enter_blob->channel->base->uniqueid, progress->transferee)) {
268 /* Don't care */
269 return;
270 }
271
272 if (!progress->transfer_data->completed) {
273 /* We can't act on this message because the transfer_channel_data doesn't show that
274 * the transfer is ready to progress */
275 return;
276 }
277
278 /* OMG the transferee is joining a bridge. His call got answered! */
279 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
280 if (notification) {
281 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
282 ao2_cleanup(notification);
283 }
284 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
285 }
286
287 chan = ast_channel_get_by_name(progress->transferee);
288 if (!chan) {
289 /* The channel is already gone */
290 return;
291 }
292
293 ast_channel_lock(chan);
294 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as it has joined a bridge\n",
295 ast_channel_name(chan));
296 ast_framehook_detach(chan, progress->framehook);
297 ast_channel_unlock(chan);
298
299 ast_channel_unref(chan);
300}
301
302/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer */
303static struct ast_frame *refer_progress_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
304{
305 struct refer_progress *progress = data;
306 struct refer_progress_notification *notification = NULL;
307
308 /* We only care about frames *to* the channel */
309 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
310 return f;
311 }
312
313 /* If the completed flag hasn't been raised, skip this pass. */
314 if (!progress->transfer_data->completed) {
315 return f;
316 }
317
318 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
319 if (f->frametype == AST_FRAME_VOICE && !progress->subclass) {
320 /* Media is passing without progress, this means the call has been answered */
321 progress->subclass = AST_CONTROL_ANSWER;
322 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
323 } else if (f->frametype == AST_FRAME_CONTROL) {
324 /* Based on the control frame being written we can send a NOTIFY advising of the progress */
326 /* Don't set progress->subclass; an ANSWER can still follow */
327 notification = refer_progress_notification_alloc(progress, 180, PJSIP_EVSUB_STATE_ACTIVE);
328 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
329 progress->subclass = f->subclass.integer;
330 notification = refer_progress_notification_alloc(progress, 486, PJSIP_EVSUB_STATE_TERMINATED);
331 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
332 progress->subclass = f->subclass.integer;
333 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
334 } else if (f->subclass.integer == AST_CONTROL_PROGRESS) {
335 /* Don't set progress->subclass; an ANSWER can still follow */
336 notification = refer_progress_notification_alloc(progress, 183, PJSIP_EVSUB_STATE_ACTIVE);
337 } else if (f->subclass.integer == AST_CONTROL_PROCEEDING) {
338 /* Don't set progress->subclass; an ANSWER can still follow */
339 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
340 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
341 progress->subclass = f->subclass.integer;
342 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
343 }
344 }
345
346 /* If a notification is due to be sent push it to the thread pool */
347 if (notification) {
348 /* If the subscription is being terminated we don't need the frame hook any longer */
349 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
350 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
351 ast_channel_name(chan));
352 ast_framehook_detach(chan, progress->framehook);
353 }
354
355 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
356 ao2_cleanup(notification);
357 }
358 }
359
360 return f;
361}
362
363/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer. Used for the ari-only mode */
365{
366 struct refer_progress *progress = data;
367 struct refer_progress_notification *notification = NULL;
368
369 /* We only care about frames *to* the channel */
370 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
371 return f;
372 }
373
374 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
377 && f->datalen >= sizeof(enum ast_control_transfer)) {
379 switch (*message) {
381 notification = refer_progress_notification_alloc(progress, 603, PJSIP_EVSUB_STATE_TERMINATED);
382 break;
384 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
385 break;
387 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
388 break;
390 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
391 break;
393 break;
394 }
395 progress->ari_state->last_response = *message;
396 }
397
398 /* If a notification is due to be sent push it to the thread pool */
399 if (notification) {
400 /* If the subscription is being terminated we don't need the frame hook any longer */
401 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
402 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
403 ast_channel_name(chan));
404 ast_framehook_detach(chan, progress->framehook);
405 }
406
407 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
408 ao2_cleanup(notification);
409 }
410 }
411
412 return f;
413}
414
415/*! \brief Destroy callback for monitoring framehook */
416static void refer_progress_framehook_destroy(void *data)
417{
418 struct refer_progress *progress = data;
419 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
420
421 if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
422 ao2_cleanup(notification);
423 }
424
425 if (progress->bridge_sub) {
426 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
427 }
428
430}
431
432/*!
433 * \brief Callback for REFER subscription state changes
434 * \see refer_progress_notify
435 *
436 * The documentation attached to refer_progress_notify has more
437 * information about the locking issues with cleaning up
438 * the subscription.
439 *
440 * \note pjproject holds the dialog lock while calling this function.
441 */
442static void refer_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
443{
444 struct refer_progress *progress = pjsip_evsub_get_mod_data(sub, refer_progress_module.id);
445
446 /*
447 * If being destroyed, remove the progress object from the subscription
448 * and release the reference it had.
449 */
450 if (progress && (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)) {
451 pjsip_evsub_set_mod_data(progress->sub, refer_progress_module.id, NULL);
452 progress->sub = NULL;
454 }
455}
456
457/*! \brief Callback structure for subscription */
458static pjsip_evsub_user refer_progress_evsub_cb = {
459 .on_evsub_state = refer_progress_on_evsub_state,
460};
461
462static int dlg_releaser_task(void *data) {
463 pjsip_dlg_dec_session((pjsip_dialog *)data, &refer_progress_module);
464 return 0;
465}
466
467/*! \brief Destructor for REFER progress sutrcture */
468static void refer_progress_destroy(void *obj)
469{
470 struct refer_progress *progress = obj;
471
472 if (progress->bridge_sub) {
473 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
474 }
475
476 if (progress->dlg) {
477 /*
478 * Although the dlg session count was incremented in a pjsip servant
479 * thread, there's no guarantee that the last thread to unref this progress
480 * object was one. Before we decrement, we need to make sure that this
481 * is either a servant thread or that we push the decrement to a
482 * serializer that is one.
483 *
484 * Because pjsip_dlg_dec_session requires the dialog lock, we don't want
485 * to wait on the task to complete if we had to push it to a serializer.
486 */
488 pjsip_dlg_dec_session(progress->dlg, &refer_progress_module);
489 } else {
491 }
492 }
493
494 ao2_cleanup(progress->transfer_data);
495 ao2_cleanup(progress->ari_state);
496
497 ast_free(progress->transferee);
499}
500
501/*! \brief Internal helper function which sets up a refer progress structure if needed */
502static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata, struct refer_progress **progress)
503{
504 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
505 pjsip_generic_string_hdr *refer_sub = NULL;
506 const pj_str_t str_true = { "true", 4 };
507 pjsip_hdr hdr_list;
508 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
509
510 *progress = NULL;
511
512 /* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */
513 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
514 if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4))) {
515 return 0;
516 }
517
518 if (!(*progress = ao2_alloc(sizeof(struct refer_progress), refer_progress_destroy))) {
519 return -1;
520 }
521
522 ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
524
525 (*progress)->refer_blind_progress = session->endpoint->refer_blind_progress;
526
527 (*progress)->framehook = -1;
528
529 /* Create name with seq number appended. */
530 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/refer/%s",
532
533 if (!((*progress)->serializer = ast_sip_create_serializer(tps_name))) {
534 goto error;
535 }
536
537 /* Create the implicit subscription for monitoring of this transfer */
538 if (pjsip_xfer_create_uas(session->inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
539 goto error;
540 }
541
542 /* To prevent a potential deadlock we need the dialog so we can lock/unlock */
543 (*progress)->dlg = session->inv_session->dlg;
544 /* We also need to make sure it stays around until we're done with it */
545 pjsip_dlg_inc_session((*progress)->dlg, &refer_progress_module);
546
547
548 /* Associate the REFER progress structure with the subscription */
549 ao2_ref(*progress, +1);
550 pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
551
552 pj_list_init(&hdr_list);
553 if (refer_sub) {
554 pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->inv_session->dlg->pool, &str_refer_sub, &str_true);
555
556 pj_list_push_back(&hdr_list, hdr);
557 }
558
559 /* Accept the REFER request */
560 ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress);
561 pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
562
563 return 0;
564
565error:
567 *progress = NULL;
568 return -1;
569}
570
571/*! \brief Structure for attended transfer task */
573 /*! \brief Transferer session */
575 /*! \brief Transferer channel */
577 /*! \brief Second transferer session */
579 /*! \brief Optional refer progress structure */
581};
582
583/*! \brief Destructor for attended transfer task */
584static void refer_attended_destroy(void *obj)
585{
586 struct refer_attended *attended = obj;
587
588 ao2_cleanup(attended->transferer);
591 ao2_cleanup(attended->progress);
592}
593
594/*! \brief Allocator for attended transfer task */
597 struct refer_progress *progress)
598{
599 struct refer_attended *attended;
600
601 attended = ao2_alloc_options(sizeof(*attended), refer_attended_destroy,
603 if (!attended) {
604 return NULL;
605 }
606
607 ao2_ref(transferer, +1);
608 attended->transferer = transferer;
613
614 if (progress) {
615 ao2_ref(progress, +1);
616 attended->progress = progress;
617 }
618
619 return attended;
620}
621
622static int session_end_if_deferred_task(void *data)
623{
624 struct ast_sip_session *session = data;
625
627 ao2_ref(session, -1);
628 return 0;
629}
630
631static int defer_termination_cancel_task(void *data)
632{
633 struct ast_sip_session *session = data;
634
637 ao2_ref(session, -1);
638 return 0;
639}
640
641/*!
642 * \internal
643 * \brief Convert transfer enum to SIP response code.
644 * \since 13.3.0
645 *
646 * \param xfer_code Core transfer function enum result.
647 *
648 * \return SIP response code
649 */
651{
652 int response;
653
654 response = 503;
655 switch (xfer_code) {
657 response = 400;
658 break;
660 response = 403;
661 break;
663 response = 500;
664 break;
666 response = 200;
667 break;
668 }
669 return response;
670}
671
672/*! \brief Task for attended transfer executed by attended->transferer_second serializer */
673static int refer_attended_task(void *data)
674{
675 struct refer_attended *attended = data;
676 int response;
677 int (*task_cb)(void *data);
678
679 if (attended->transferer_second->channel) {
680 ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
683
685 attended->transferer_chan,
686 attended->transferer_second->channel));
687
688 ast_debug(3, "Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
691 response);
692 } else {
693 ast_debug(3, "Received REFER request on channel '%s' but other channel has gone.\n",
695 response = 603;
696 }
697
698 if (attended->progress) {
699 struct refer_progress_notification *notification;
700
701 notification = refer_progress_notification_alloc(attended->progress, response,
702 PJSIP_EVSUB_STATE_TERMINATED);
703 if (notification) {
704 if (ast_sip_push_task(attended->progress->serializer, refer_progress_notify, notification)) {
705 ao2_cleanup(notification);
706 }
707 }
708 }
709
710 if (response == 200) {
712 } else {
714 }
716 task_cb, attended->transferer)) {
717 /* Gave the ref to the pushed task. */
718 attended->transferer = NULL;
719 } else {
720 /* Do this anyway even though it is the wrong serializer. */
722 }
723
724 ao2_ref(attended, -1);
725 return 0;
726}
727
728/*! \brief Structure for blind transfer callback details */
730 /*! \brief Context being used for transfer */
731 const char *context;
732 /*! \brief Optional progress structure */
734 /*! \brief REFER message */
735 pjsip_rx_data *rdata;
736 /*! \brief Optional Replaces header */
737 pjsip_replaces_hdr *replaces;
738 /*! \brief Optional Refer-To header */
739 pjsip_sip_uri *refer_to;
740 /*! \brief Attended transfer flag */
741 unsigned int attended:1;
742};
743
744/*! \brief Blind transfer callback function */
745static void refer_blind_callback(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
746 enum ast_transfer_type transfer_type)
747{
748 struct refer_blind *refer = user_data_wrapper->data;
749 pjsip_generic_string_hdr *referred_by;
750
751 static const pj_str_t str_referred_by = { "Referred-By", 11 };
752 static const pj_str_t str_referred_by_s = { "b", 1 };
753 const char *get_xfrdata;
754
755 pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
756
757 if (refer->progress && !refer->attended && !refer->progress->refer_blind_progress) {
758 /* If blind transfer and endpoint doesn't want to receive all the progress details */
760 PJSIP_EVSUB_STATE_TERMINATED);
761
762 if (notification) {
763 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
764 ao2_cleanup(notification);
765 }
766 }
767 } else if (refer->progress) {
768 /* If attended transfer and progress monitoring is being done attach a frame hook so we can monitor it */
769 struct ast_framehook_interface hook = {
771 .event_cb = refer_progress_framehook,
773 .data = refer->progress,
774 .disable_inheritance = 1,
775 };
776
778 if (!refer->progress->transferee) {
780 PJSIP_EVSUB_STATE_TERMINATED);
781
782 ast_log(LOG_WARNING, "Could not copy channel name '%s' during transfer - assuming success\n",
783 ast_channel_name(chan));
784
785 if (notification) {
786 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
787 ao2_cleanup(notification);
788 }
789 }
790 }
791
792 /* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
793 ao2_ref(user_data_wrapper, +1);
794 refer->progress->transfer_data = user_data_wrapper;
795
796 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
797 ao2_ref(refer->progress, +1);
798
799 /* If we can't attach a frame hook for whatever reason send a notification of success immediately */
800 ast_channel_lock(chan);
801 refer->progress->framehook = ast_framehook_attach(chan, &hook);
802 ast_channel_unlock(chan);
803 if (refer->progress->framehook < 0) {
805 PJSIP_EVSUB_STATE_TERMINATED);
806
807 ast_log(LOG_WARNING, "Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
808 ast_channel_name(chan));
809
810 if (notification) {
811 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
812 ao2_cleanup(notification);
813 }
814 }
815
816 ao2_cleanup(refer->progress);
817 }
818
819 /* We need to bump the reference count for the stasis subscription */
820 ao2_ref(refer->progress, +1);
821 /* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
822 * detect if the transfer target has answered the call
823 */
825 if (!refer->progress->bridge_sub) {
827 PJSIP_EVSUB_STATE_TERMINATED);
828
829 ast_log(LOG_WARNING, "Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success\n",
830 ast_channel_name(chan));
831
832 if (notification) {
833 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
834 ao2_cleanup(notification);
835 }
836 }
837
838 ast_channel_lock(chan);
840 ast_channel_unlock(chan);
841
842 ao2_cleanup(refer->progress);
843 } else {
847 }
848 }
849
850 pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL));
851
852 ast_channel_lock(chan);
853 if ((get_xfrdata = pbx_builtin_getvar_helper(chan, "GET_TRANSFERRER_DATA"))) {
854 get_xfrdata = ast_strdupa(get_xfrdata);
855 }
856 ast_channel_unlock(chan);
857 if (!ast_strlen_zero(get_xfrdata)) {
858 const pjsip_msg * msg = refer->rdata->msg_info.msg;
859 const struct pjsip_hdr *end = &msg->hdr;
860 struct pjsip_hdr *hdr = end->next;
861 struct ast_str *pbxvar = ast_str_create(64); /* initial buffer for variable name, extended on demand */
862 char buf[4096]; /* should be enough for one header value */
863 const char *prefix = get_xfrdata;
864
865 /* The '*' alone matches all headers. */
866 if (!strcmp(prefix, "*")) {
867 prefix = "";
868 }
869 if (pbxvar) {
870 for (; hdr != end; hdr = hdr->next) {
871 if (!pj_strnicmp2(&hdr->name, prefix, strlen(prefix))) {
872 const int hdr_name_strlen = pj_strlen(&hdr->name);
873 const int hdr_name_bytes = hdr_name_strlen + 1; /* +1 for string NULL terminator */
874 char hdr_name[hdr_name_bytes];
875 int len;
876 char *value_str;
877
878 ast_copy_pj_str(hdr_name, &hdr->name, hdr_name_bytes);
879 len = pjsip_hdr_print_on(hdr, buf, sizeof(buf) - 1);
880 if (len < 0) {
881 /* ignore too long headers */
882 ast_log(LOG_WARNING, "Could not store header '%s' from transfer on channel '%s' - too long text\n", hdr_name, ast_channel_name(chan));
883 continue;
884 }
885 buf[len] = '\0';
886
887 /* Get value - remove header name (before ':') from buf and trim blanks. */
888 value_str = strchr(buf, ':');
889 if (!value_str) {
890 /* Ignore header without value */
891 continue;
892 }
893 value_str = ast_strip(value_str + 1); /* +1 to get string right after the ':' delimiter (i.e. header value) */
894
895 ast_str_set(&pbxvar, -1, "~HASH~TRANSFER_DATA~%.*s~", hdr_name_strlen, hdr_name);
896 pbx_builtin_setvar_helper(chan, ast_str_buffer(pbxvar), value_str);
897 ast_debug(5, "On channel '%s' set TRANSFER_DATA variable '%s' to value '%s' \n", ast_channel_name(chan), hdr_name, value_str);
898 }
899 }
900 ast_free(pbxvar);
901 } else {
902 ast_log(LOG_ERROR, "Channel '%s' failed to allocate buffer for TRANSFER_DATA variable\n", ast_channel_name(chan));
903 }
904 }
905
906 referred_by = pjsip_msg_find_hdr_by_names(refer->rdata->msg_info.msg,
907 &str_referred_by, &str_referred_by_s, NULL);
908 if (referred_by) {
909 size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
910 char *uri = ast_alloca(uri_size);
911
912 ast_copy_pj_str(uri, &referred_by->hvalue, uri_size);
913 pbx_builtin_setvar_helper(chan, "__SIPREFERREDBYHDR", S_OR(uri, NULL));
914 } else {
915 pbx_builtin_setvar_helper(chan, "SIPREFERREDBYHDR", NULL);
916 }
917
918 if (refer->replaces) {
919 char replaces[512];
920 char *replaces_val = NULL;
921 int len;
922
923 len = pjsip_hdr_print_on(refer->replaces, replaces, sizeof(replaces) - 1);
924 if (len != -1) {
925 /* pjsip_hdr_print_on does not NULL terminate the buffer */
926 replaces[len] = '\0';
927 replaces_val = replaces + sizeof("Replaces:");
928 }
929 pbx_builtin_setvar_helper(chan, "__SIPREPLACESHDR", replaces_val);
930 } else {
931 pbx_builtin_setvar_helper(chan, "SIPREPLACESHDR", NULL);
932 }
933
934 if (refer->refer_to) {
935 char refer_to[PJSIP_MAX_URL_SIZE];
936
937 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->refer_to, refer_to, sizeof(refer_to));
938 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", S_OR(refer_to, NULL));
939 } else {
940 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", NULL);
941 }
942}
943
944/*!
945 * \internal
946 * \brief Set the passed in context variable to the determined transfer context.
947 * \since 13.3.0
948 *
949 * \param context Set to the determined transfer context.
950 * \param session INVITE dialog SIP session.
951 */
952#define DETERMINE_TRANSFER_CONTEXT(context, session) \
953 do { \
954 ast_channel_lock((session)->channel); \
955 context = pbx_builtin_getvar_helper((session)->channel, "TRANSFER_CONTEXT"); \
956 if (ast_strlen_zero(context)) { \
957 context = (session)->endpoint->context; \
958 } else { \
959 context = ast_strdupa(context); \
960 } \
961 ast_channel_unlock((session)->channel); \
962 } while (0) \
963
964struct refer_data {
967 char *from;
968 char *refer_to;
970};
971
972static void refer_data_destroy(void *obj)
973{
974 struct refer_data *rdata = obj;
975
976 ast_free(rdata->destination);
977 ast_free(rdata->from);
978 ast_free(rdata->refer_to);
979
980 ast_refer_destroy(rdata->refer);
981}
982
983static struct refer_data *refer_data_create(const struct ast_refer *refer)
984{
985 char *uri_params;
986 const char *destination;
988
989 if (!rdata) {
990 return NULL;
991 }
992
993 /* typecast to suppress const warning */
994 rdata->refer = ast_refer_ref((struct ast_refer *) refer);
996
997 /* To starts with 'pjsip:' which needs to be removed. */
998 if (!(destination = strchr(destination, ':'))) {
999 goto failure;
1000 }
1001 ++destination;/* Now skip the ':' */
1002
1004 if (!rdata->destination) {
1005 goto failure;
1006 }
1007
1009 if (!rdata->from) {
1010 goto failure;
1011 }
1012
1014 if (!rdata->refer_to) {
1015 goto failure;
1016 }
1018
1019 /*
1020 * Sometimes from URI can contain URI parameters, so remove them.
1021 *
1022 * sip:user;user-options@domain;uri-parameters
1023 */
1024 uri_params = strchr(rdata->from, '@');
1025 if (uri_params && (uri_params = strchr(uri_params, ';'))) {
1026 *uri_params = '\0';
1027 }
1028 return rdata;
1029
1030failure:
1031 ao2_cleanup(rdata);
1032 return NULL;
1033}
1034
1035/*!
1036 * \internal
1037 * \brief Checks if the given refer var name should be blocked.
1038 *
1039 * \details Some headers are not allowed to be overridden by the user.
1040 * Determine if the given var header name from the user is blocked for
1041 * an outgoing REFER.
1042 *
1043 * \param name name of header to see if it is blocked.
1044 *
1045 * \retval TRUE if the given header is blocked.
1046 */
1047static int is_refer_var_blocked(const char *name)
1048{
1049 int i;
1050
1051 /* Don't block the Max-Forwards header because the user can override it */
1052 static const char *hdr[] = {
1053 "To",
1054 "From",
1055 "Via",
1056 "Route",
1057 "Contact",
1058 "Call-ID",
1059 "CSeq",
1060 "Allow",
1061 "Content-Length",
1062 "Content-Type",
1063 "Request-URI",
1064 };
1065
1066 for (i = 0; i < ARRAY_LEN(hdr); ++i) {
1067 if (!strcasecmp(name, hdr[i])) {
1068 /* Block addition of this header. */
1069 return 1;
1070 }
1071 }
1072 return 0;
1073}
1074
1075/*!
1076 * \internal
1077 * \brief Copies any other refer vars over to the request headers.
1078 *
1079 * \param refer The refer structure to copy headers from
1080 * \param tdata The SIP transmission data
1081 */
1082static enum pjsip_status_code vars_to_headers(const struct ast_refer *refer, pjsip_tx_data *tdata)
1083{
1084 const char *name;
1085 const char *value;
1087
1088 for (iter = ast_refer_var_iterator_init(refer);
1091 if (!is_refer_var_blocked(name)) {
1092 ast_sip_add_header(tdata, name, value);
1093 }
1094 }
1096
1097 return PJSIP_SC_OK;
1098}
1099
1101 pjsip_dialog *dlg;
1103};
1104
1105/*! \brief REFER Out-of-dialog module, used to attach session data structure to subscription */
1106static pjsip_module refer_out_of_dialog_module = {
1107 .name = { "REFER Out-of-dialog Module", 26 },
1108 .id = -1,
1109 .on_tx_request = refer_on_tx_request,
1110 /* Ensure that we are called after res_pjsp_nat module and before transport priority */
1111 .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 4,
1112};
1113
1114/*! \brief Helper function which returns the name-addr of the Refer-To header or NULL */
1115static pjsip_uri *get_refer_to_uri(pjsip_tx_data *tdata)
1116{
1117 const pj_str_t REFER_TO = { "Refer-To", 8 };
1118 pjsip_generic_string_hdr *refer_to;
1119 pjsip_uri *parsed_uri;
1120
1121 if (!(refer_to = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL))
1122 || !(parsed_uri = pjsip_parse_uri(tdata->pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0))
1123 || (!PJSIP_URI_SCHEME_IS_SIP(parsed_uri) && !PJSIP_URI_SCHEME_IS_SIPS(parsed_uri))) {
1124 return NULL;
1125 }
1126
1127 return parsed_uri;
1128}
1129
1130static pj_status_t refer_on_tx_request(pjsip_tx_data *tdata) {
1131 RAII_VAR(struct ast_str *, refer_to_str, ast_str_create(PJSIP_MAX_URL_SIZE), ast_free_ptr);
1132 const pj_str_t REFER_TO = { "Refer-To", 8 };
1133 pjsip_generic_string_hdr *refer_to_hdr;
1134 pjsip_dialog *dlg;
1135 struct refer_data *refer_data;
1136 pjsip_uri *parsed_uri;
1137 pjsip_sip_uri *refer_to_uri;
1138
1139 /*
1140 * If this is a request in response to a 401/407 Unauthorized challenge, the
1141 * Refer-To URI has been rewritten already, so don't attempt to re-write it again.
1142 * Checking for presence of the Authorization header is not an ideal solution. We do this because
1143 * there exists some race condition where this dialog is not the same as the one used
1144 * to send the original request in which case we don't have the correct refer_data.
1145 */
1146 if (!refer_to_str
1147 || pjsip_msg_find_hdr(tdata->msg, PJSIP_H_AUTHORIZATION, NULL)
1148 || !(dlg = pjsip_tdata_get_dlg(tdata))
1149 || !(refer_data = pjsip_dlg_get_mod_data(dlg, refer_out_of_dialog_module.id))
1150 || !refer_data->to_self
1151 || !(parsed_uri = get_refer_to_uri(tdata))) {
1152 goto out;
1153 }
1154 refer_to_uri = pjsip_uri_get_uri(parsed_uri);
1155 ast_sip_rewrite_uri_to_local(refer_to_uri, tdata);
1156
1157 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, parsed_uri, ast_str_buffer(refer_to_str), ast_str_size(refer_to_str));
1158 refer_to_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL);
1159 pj_strdup2(tdata->pool, &refer_to_hdr->hvalue, ast_str_buffer(refer_to_str));
1160
1161out:
1162 return PJ_SUCCESS;
1163}
1164
1165static int refer_unreference_dialog(void *obj)
1166{
1167 struct refer_out_of_dialog *data = obj;
1168
1169 /* This is why we keep the dialog on the subscription. When the subscription
1170 * is destroyed, there is no guarantee that the underlying dialog is ready
1171 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1172 * either. The dialog could be destroyed before our subscription is. We fix
1173 * this problem by keeping a reference to the dialog until it is time to
1174 * destroy the subscription.
1175 */
1176 pjsip_dlg_dec_session(data->dlg, &refer_out_of_dialog_module);
1177 data->dlg = NULL;
1178
1179 return 0;
1180}
1181/*! \brief Destructor for REFER out of dialog structure */
1182static void refer_out_of_dialog_destroy(void *obj) {
1183 struct refer_out_of_dialog *data = obj;
1184
1185 if (data->dlg) {
1186 /* ast_sip_push_task_wait_servant should not be called in a destructor,
1187 * however in this case it seems to be fine.
1188 */
1190 }
1191}
1192
1193/*!
1194 * \internal
1195 * \brief Callback function to report status of implicit REFER-NOTIFY subscription.
1196 *
1197 * This function will be called on any state change in the REFER-NOTIFY subscription.
1198 * Its primary purpose is to report SUCCESS/FAILURE of a refer initiated via
1199 * \ref refer_send as well as to terminate the subscription, if necessary.
1200 */
1201static void refer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
1202{
1203 pjsip_tx_data *tdata;
1204 RAII_VAR(struct ast_sip_endpoint *, endpt, NULL, ao2_cleanup);
1206 int refer_success;
1207 int res = 0;
1208
1209 if (!event) {
1210 return;
1211 }
1212
1213 refer_data = pjsip_evsub_get_mod_data(sub, refer_out_of_dialog_module.id);
1214 if (!refer_data || !refer_data->dlg) {
1215 return;
1216 }
1217
1219
1220 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
1221 /* Check if subscription is suppressed and terminate and send completion code, if so. */
1222 pjsip_rx_data *rdata;
1223 pjsip_generic_string_hdr *refer_sub;
1224 const pj_str_t REFER_SUB = { "Refer-Sub", 9 };
1225
1226 ast_debug(3, "Refer accepted by %s\n", endpt ? ast_sorcery_object_get_id(endpt) : "(unknown endpoint)");
1227
1228 /* Check if response message */
1229 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1230 rdata = event->body.tsx_state.src.rdata;
1231
1232 /* Find Refer-Sub header */
1233 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &REFER_SUB, NULL);
1234
1235 /* Check if subscription is suppressed. If it is, the far end will not terminate it,
1236 * and the subscription will remain active until it times out. Terminating it here
1237 * eliminates the unnecessary timeout.
1238 */
1239 if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
1240 /* Since no subscription is desired, assume that call has been referred successfully
1241 * and terminate subscription.
1242 */
1243 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1244 pjsip_evsub_terminate(sub, PJ_TRUE);
1245 res = -1;
1246 }
1247 }
1248 } else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
1249 pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
1250 /* Check for NOTIFY complete or error. */
1251 pjsip_msg *msg;
1252 pjsip_msg_body *body;
1253 pjsip_status_line status_line = { .code = 0 };
1254 pj_bool_t is_last;
1255 pj_status_t status;
1256
1257 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1258 pjsip_rx_data *rdata;
1259 pj_str_t refer_str;
1260 pj_cstr(&refer_str, "REFER");
1261
1262 rdata = event->body.tsx_state.src.rdata;
1263 msg = rdata->msg_info.msg;
1264
1265 if (msg->type == PJSIP_RESPONSE_MSG
1266 && (event->body.tsx_state.tsx->status_code == 401
1267 || event->body.tsx_state.tsx->status_code == 407)
1268 && pj_stristr(&refer_str, &event->body.tsx_state.tsx->method.name)
1269 && ++refer_data->authentication_challenge_count < MAX_RX_CHALLENGES
1270 && endpt) {
1271
1272 if (!ast_sip_create_request_with_auth(&endpt->outbound_auths,
1273 event->body.tsx_state.src.rdata, event->body.tsx_state.tsx->last_tx, &tdata)) {
1274 /* Send authed REFER */
1276 goto out;
1277 }
1278 }
1279
1280 if (msg->type == PJSIP_REQUEST_MSG) {
1281 if (!pjsip_method_cmp(&msg->line.req.method, pjsip_get_notify_method())) {
1282 body = msg->body;
1283 if (body && !pj_stricmp2(&body->content_type.type, "message")
1284 && !pj_stricmp2(&body->content_type.subtype, "sipfrag")) {
1285 pjsip_parse_status_line((char *)body->data, body->len, &status_line);
1286 }
1287 }
1288 } else {
1289 status_line.code = msg->line.status.code;
1290 status_line.reason = msg->line.status.reason;
1291 }
1292 } else {
1293 status_line.code = 500;
1294 status_line.reason = *pjsip_get_status_text(500);
1295 }
1296
1297 is_last = (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED);
1298 /* If the status code is >= 200, the subscription is finished. */
1299 if (status_line.code >= 200 || is_last) {
1300 res = -1;
1301
1302 refer_success = status_line.code >= 200 && status_line.code < 300;
1303
1304 /* If subscription not terminated and subscription is finished (status code >= 200)
1305 * terminate it */
1306 if (!is_last) {
1307 pjsip_tx_data *tdata;
1308
1309 status = pjsip_evsub_initiate(sub, pjsip_get_subscribe_method(), 0, &tdata);
1310 if (status == PJ_SUCCESS) {
1311 pjsip_evsub_send_request(sub, tdata);
1312 }
1313 }
1314 ast_debug(3, "Refer completed: %d %.*s (%s)\n",
1315 status_line.code,
1316 (int)status_line.reason.slen, status_line.reason.ptr,
1317 refer_success ? "Success" : "Failure");
1318 }
1319 }
1320
1321out:
1322 if (res) {
1324 }
1325}
1326
1327/*!
1328 * \internal
1329 * \brief Send a REFER
1330 *
1331 * \param data The outbound refer data structure
1332 *
1333 * \return 0: success, -1: failure
1334 */
1335static int refer_send(void *data)
1336{
1337 struct refer_data *rdata = data; /* The caller holds a reference */
1338 pjsip_tx_data *tdata;
1339 pjsip_evsub *sub;
1340 pj_str_t tmp;
1341 char refer_to_str[PJSIP_MAX_URL_SIZE];
1342 char disp_name_escaped[128];
1343 struct refer_out_of_dialog *refer;
1344 struct pjsip_evsub_user xfer_cb;
1345 RAII_VAR(char *, uri, NULL, ast_free);
1346 RAII_VAR(char *, tmp_str, NULL, ast_free);
1347 RAII_VAR(char *, display_name, NULL, ast_free);
1348 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1349 RAII_VAR(struct ast_sip_endpoint *, refer_to_endpoint, NULL, ao2_cleanup);
1350
1351 endpoint = ast_sip_get_endpoint(rdata->destination, 1, &uri);
1352 if (!endpoint) {
1354 "PJSIP REFER - Could not find endpoint '%s' and no default outbound endpoint configured\n",
1355 rdata->destination);
1356 return -1;
1357 }
1358 ast_debug(3, "Request URI: %s\n", uri);
1359
1360 refer_to_endpoint = ast_sip_get_endpoint(rdata->refer_to, 0, &tmp_str);
1361 if (!tmp_str) {
1362 ast_log(LOG_WARNING, "PJSIP REFER - Refer to not a valid resource identifier or SIP URI\n");
1363 return -1;
1364 }
1365 if (!(refer = ao2_alloc(sizeof(struct refer_out_of_dialog), refer_out_of_dialog_destroy))) {
1366 ast_log(LOG_ERROR, "PJSIP REFER - Could not allocate resources.\n");
1367 return -1;
1368 }
1369 /* The dialog will be terminated in the subscription event callback
1370 * when the subscription has terminated. */
1372 refer->dlg = ast_sip_create_dialog_uac(endpoint, uri, NULL);
1373 if (!refer->dlg) {
1374 ast_log(LOG_WARNING, "PJSIP REFER - Could not create dialog\n");
1375 ao2_cleanup(refer);
1376 return -1;
1377 }
1378 ast_sip_dialog_set_endpoint(refer->dlg, endpoint);
1379
1380 pj_bzero(&xfer_cb, sizeof(xfer_cb));
1381 xfer_cb.on_evsub_state = &refer_client_on_evsub_state;
1382 if (pjsip_xfer_create_uac(refer->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
1383 ast_log(LOG_WARNING, "PJSIP REFER - Could not create uac\n");
1384 ao2_cleanup(refer);
1385 return -1;
1386 }
1387
1388 display_name = ast_refer_get_var_and_unlink(rdata->refer, "display_name");
1389 if (display_name) {
1390 ast_escape_quoted(display_name, disp_name_escaped, sizeof(disp_name_escaped));
1391 snprintf(refer_to_str, sizeof(refer_to_str), "\"%s\" <%s>", disp_name_escaped, tmp_str);
1392 } else {
1393 snprintf(refer_to_str, sizeof(refer_to_str), "%s", tmp_str);
1394 }
1395
1396 /* refer_out_of_dialog_module requires a reference to dlg
1397 * which will be released in refer_client_on_evsub_state()
1398 * when the implicit REFER subscription terminates */
1399 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, refer);
1400 if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, refer_to_str), &tdata) != PJ_SUCCESS) {
1401 ast_log(LOG_WARNING, "PJSIP REFER - Could not create request\n");
1402 goto failure;
1403 }
1404
1405 if (refer_to_endpoint && rdata->to_self) {
1406 pjsip_dlg_add_usage(refer->dlg, &refer_out_of_dialog_module, rdata);
1407 }
1408
1409 ast_sip_update_to_uri(tdata, uri);
1410 ast_sip_update_from(tdata, rdata->from);
1411
1412 /*
1413 * This copies any headers found in the refer's variables to
1414 * tdata.
1415 */
1416 vars_to_headers(rdata->refer, tdata);
1417 ast_debug(1, "Sending REFER to '%s' (via endpoint %s) from '%s'\n",
1418 rdata->destination, ast_sorcery_object_get_id(endpoint), rdata->from);
1419
1420 if (pjsip_xfer_send_request(sub, tdata) == PJ_SUCCESS) {
1421 return 0;
1422 }
1423
1424failure:
1425 ao2_cleanup(refer);
1426 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1427 pjsip_evsub_terminate(sub, PJ_FALSE);
1428 return -1;
1429}
1430
1431static int sip_refer_send(const struct ast_refer *refer)
1432{
1433 struct refer_data *rdata;
1434 int res;
1435
1437 ast_log(LOG_ERROR, "SIP REFER - a 'To' URI must be specified\n");
1438 return -1;
1439 }
1440
1441 rdata = refer_data_create(refer);
1442 if (!rdata) {
1443 return -1;
1444 }
1445
1447 ao2_ref(rdata, -1);
1448
1449 return res;
1450}
1451
1452static const struct ast_refer_tech refer_tech = {
1453 .name = "pjsip",
1454 .refer_send = sip_refer_send,
1455};
1456
1457static char *copy_string(struct pj_str_t *str)
1458{
1459 int len = pj_strlen(str) + 1;
1460 char *dst = ast_malloc(len);
1461 if (!dst) {
1462 return NULL;
1463 }
1464 ast_copy_pj_str(dst, str, len);
1465 return dst;
1466}
1467
1468static int add_refer_param(struct ast_refer_params *params, const char *key, struct pj_str_t *str)
1469{
1470 struct ast_refer_param param;
1471
1472 param.param_name = ast_strdup(key);
1473 if (!param.param_name) {
1474 return 0;
1475 }
1476
1477 param.param_value = copy_string(str);
1478 if (!param.param_value) {
1479 ast_free((char *) param.param_name);
1480 return 0;
1481 }
1482
1483 if (AST_VECTOR_APPEND(params, param) != 0) {
1484 ast_free((char *) param.param_name);
1485 ast_free((char *) param.param_value);
1486 return 0;
1487 }
1488 return 1;
1489}
1490
1491
1492static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
1493 pjsip_param *replaces_param, struct refer_progress *progress)
1494{
1495 int parsed_len;
1496 pjsip_replaces_hdr *replaces;
1497 pjsip_generic_string_hdr *referred_hdr;
1498
1499
1501
1502 struct ast_framehook_interface hook = {
1504 .event_cb = refer_ari_progress_framehook,
1506 .data = progress,
1507 .disable_inheritance = 1,
1508 };
1509
1510 static const pj_str_t str_referred_by = { "Referred-By", 11 };
1511 static const pj_str_t str_referred_by_s = { "b", 1 };
1512 static const pj_str_t str_replaces = { "Replaces", 8 };
1513
1514
1516 if (!state) {
1517 return 500;
1518 }
1519
1520 state->last_response = AST_TRANSFER_INVALID;
1521
1522 state->params = ao2_alloc(sizeof(struct ast_refer_params), refer_params_destroy);
1523 if (!state->params) {
1524 return 500;
1525 }
1526 AST_VECTOR_INIT(state->params, 0);
1527
1528
1529 ast_channel_ref(session->channel);
1530 state->transferer_chan = session->channel;
1531
1532 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1533 ast_copy_pj_str(state->exten, &target->user, sizeof(state->exten));
1534
1535 /*
1536 * We may want to match in the dialplan without any user
1537 * options getting in the way.
1538 */
1540
1541 referred_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg,
1542 &str_referred_by, &str_referred_by_s, NULL);
1543 if (referred_hdr) {
1544 state->referred_by = copy_string(&referred_hdr->hvalue);
1545 if (!state->referred_by) {
1546 return 500;
1547 }
1548 }
1549
1550 if (replaces_param) {
1551 pjsip_dialog *dlg;
1552 pj_str_t replaces_content = { 0, };
1553 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1554
1555 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1556 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1557 pj_strlen(&replaces_content), &parsed_len))) {
1558 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1560 return 400;
1561 }
1562
1563 dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE);
1564 if (dlg) {
1565 state->other_session = ast_sip_dialog_get_session(dlg);
1566 pjsip_dlg_dec_lock(dlg);
1567 }
1568
1569 state->protocol_id = copy_string(&replaces->call_id);
1570 if (!state->protocol_id) {
1571 return 500;
1572 }
1573
1574 if (!add_refer_param(state->params, "from", &replaces->from_tag)) {
1575 return 500;
1576 }
1577
1578 if (!add_refer_param(state->params, "to", &replaces->to_tag)) {
1579 return 500;
1580 }
1581 }
1582
1583 ao2_ref(session, +1);
1585 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted ari-only transfer but could not defer termination, rejecting\n",
1586 ast_channel_name(session->channel),
1589 return 500;
1590 }
1591 state->transferer = session;
1592
1593
1594 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
1595 ao2_ref(progress, +1);
1596 ast_channel_lock(session->channel);
1597 progress->framehook = ast_framehook_attach(session->channel, &hook);
1598 ast_channel_unlock(session->channel);
1599
1600 if (progress->framehook < 0) {
1602 return 500;
1603 }
1604
1605 if (ari_notify(state)) {
1606 ast_channel_lock(session->channel);
1607 ast_framehook_detach(session->channel, progress->framehook);
1608 progress->framehook = -1;
1610 ast_channel_unlock(session->channel);
1611 return 500;
1612 }
1613
1614 /* Transfer ownership to the progress */
1615 progress->ari_state = state;
1616 state = NULL;
1617 return 200;
1618}
1619
1620static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri,
1621 pjsip_param *replaces_param, struct refer_progress *progress)
1622{
1623 const pj_str_t str_replaces = { "Replaces", 8 };
1624 pj_str_t replaces_content;
1625 pjsip_replaces_hdr *replaces;
1626 int parsed_len;
1627 pjsip_dialog *dlg;
1628
1629 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1630
1631 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1632 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1633 pj_strlen(&replaces_content), &parsed_len))) {
1634 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1636 return 400;
1637 }
1638
1639 /* See if the dialog is local, or remote */
1640 if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
1641 RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
1642 struct refer_attended *attended;
1643
1644 pjsip_dlg_dec_lock(dlg);
1645
1646 if (!other_session) {
1647 ast_debug(3, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it\n",
1649 return 603;
1650 }
1651
1652 /* We defer actually doing the attended transfer to the other session so no deadlock can occur */
1653 if (!(attended = refer_attended_alloc(session, other_session, progress))) {
1654 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not allocate structure to complete, rejecting\n",
1656 return 500;
1657 }
1658
1660 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not defer termination, rejecting\n",
1662 ao2_cleanup(attended);
1663 return 500;
1664 }
1665
1666 /* Push it to the other session, which will have both channels with minimal locking */
1667 if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {
1670 ao2_cleanup(attended);
1671 return 500;
1672 }
1673
1674 ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
1675 ast_channel_name(session->channel));
1676
1677 return 200;
1678 } else {
1679 const char *context;
1680 struct refer_blind refer = { 0, };
1681 int response;
1682
1684
1685 if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
1686 ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but 'external_replaces' extension not found in context %s\n",
1688 return 404;
1689 }
1690
1691 refer.context = context;
1692 refer.progress = progress;
1693 refer.rdata = rdata;
1694 refer.replaces = replaces;
1695 refer.refer_to = target_uri;
1696 refer.attended = 1;
1697
1699 ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting\n",
1700 ast_channel_name(session->channel),
1702 return 500;
1703 }
1704
1706 "external_replaces", context, refer_blind_callback, &refer));
1707
1709 if (response != 200) {
1711 }
1712
1713 return response;
1714 }
1715}
1716
1717static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
1718 struct refer_progress *progress)
1719{
1720 const char *context;
1721 char exten[AST_MAX_EXTENSION];
1722 struct refer_blind refer = { 0, };
1723 int response;
1724
1725 /* If no explicit transfer context has been provided use their configured context */
1727
1728 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1729 ast_copy_pj_str(exten, &target->user, sizeof(exten));
1730
1731 /*
1732 * We may want to match in the dialplan without any user
1733 * options getting in the way.
1734 */
1736
1737 /* Uri without exten */
1738 if (ast_strlen_zero(exten)) {
1739 ast_copy_string(exten, "s", sizeof(exten));
1740 ast_debug(3, "Channel '%s' from endpoint '%s' attempted blind transfer to a target without extension. Target was set to 's@%s'\n",
1742 }
1743
1744 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
1745 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
1746 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context);
1747 return 404;
1748 }
1749
1750 refer.context = context;
1751 refer.progress = progress;
1752 refer.rdata = rdata;
1753 refer.refer_to = target;
1754 refer.attended = 0;
1755
1757 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer but could not defer termination, rejecting\n",
1758 ast_channel_name(session->channel),
1760 return 500;
1761 }
1762
1764 exten, context, refer_blind_callback, &refer));
1765
1767 if (response != 200) {
1769 }
1770
1771 return response;
1772}
1773
1774/*! \brief Structure used to retrieve channel from another session */
1776 /*! \brief Session we want the channel from */
1778 /*! \brief Channel from the session (with reference) */
1780 /*! \brief Bridge the channel is in */
1782};
1783
1784/*! \brief Task for invite replaces */
1785static int invite_replaces(void *data)
1786{
1787 struct invite_replaces *invite = data;
1788
1789 if (!invite->session->channel) {
1790 return -1;
1791 }
1792
1794 invite->channel = invite->session->channel;
1795
1797 return 0;
1798}
1799
1800static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1801{
1802 pjsip_dialog *other_dlg = NULL;
1803 pjsip_tx_data *packet;
1804 int response = 0;
1805 RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup);
1806 struct invite_replaces invite;
1807
1808 /* If a Replaces header is present make sure it is valid */
1809 if (pjsip_replaces_verify_request(rdata, &other_dlg, PJ_TRUE, &packet) != PJ_SUCCESS) {
1810 response = packet->msg->line.status.code;
1811 ast_assert(response != 0);
1812 pjsip_tx_data_dec_ref(packet);
1813 goto inv_replace_failed;
1814 }
1815
1816 /* If no other dialog exists then this INVITE request does not have a Replaces header */
1817 if (!other_dlg) {
1818 return 0;
1819 }
1820
1821 other_session = ast_sip_dialog_get_session(other_dlg);
1822 pjsip_dlg_dec_lock(other_dlg);
1823
1824 /* Don't accept an in-dialog INVITE with Replaces as it does not make much sense */
1825 if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
1826 response = 488;
1827 goto inv_replace_failed;
1828 }
1829
1830 if (!other_session) {
1831 ast_debug(3, "INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist\n",
1833 response = 481;
1834 goto inv_replace_failed;
1835 }
1836
1837 invite.session = other_session;
1838
1839 if (ast_sip_push_task_wait_serializer(other_session->serializer, invite_replaces,
1840 &invite)) {
1841 response = 481;
1842 goto inv_replace_failed;
1843 }
1844
1845 ast_channel_lock(session->channel);
1847 ast_channel_unlock(session->channel);
1848 ast_raw_answer(session->channel);
1849
1850 ast_debug(3, "INVITE with Replaces being attempted. '%s' --> '%s'\n",
1852
1853 /* Unhold the channel now, as later we are not having access to it anymore */
1854 ast_queue_unhold(session->channel);
1856
1857 if (!invite.bridge) {
1858 struct ast_channel *chan = session->channel;
1859
1860 /*
1861 * This will use a synchronous task but we aren't operating in
1862 * the serializer at this point in time, so it won't deadlock.
1863 */
1864 if (!ast_channel_move(invite.channel, chan)) {
1865 /*
1866 * We can't directly use session->channel because ast_channel_move()
1867 * does a masquerade which changes session->channel to a different
1868 * channel. To ensure we work on the right channel we store a
1869 * pointer locally before we begin so it remains valid.
1870 */
1871 ast_hangup(chan);
1872 } else {
1873 response = AST_CAUSE_FAILURE;
1874 }
1875 } else {
1876 if (ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL,
1878 response = AST_CAUSE_FAILURE;
1879 }
1880 }
1881
1882 ast_channel_unref(invite.channel);
1883 ao2_cleanup(invite.bridge);
1884
1885 if (!response) {
1886 /*
1887 * On success we cannot use session->channel in the debug message.
1888 * This thread either no longer has a ref to session->channel or
1889 * session->channel is no longer the original channel.
1890 */
1891 ast_debug(3, "INVITE with Replaces successfully completed.\n");
1892 } else {
1893 ast_debug(3, "INVITE with Replaces failed on channel '%s', hanging up with cause '%d'\n",
1894 ast_channel_name(session->channel), response);
1895 ast_channel_lock(session->channel);
1896 ast_channel_hangupcause_set(session->channel, response);
1897 ast_channel_unlock(session->channel);
1898 ast_hangup(session->channel);
1899 }
1900
1901 return 1;
1902
1903inv_replace_failed:
1904 if (session->inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
1905 ast_debug(3, "INVITE with Replaces failed on channel '%s', sending response of '%d'\n",
1906 ast_channel_name(session->channel), response);
1907 session->defer_terminate = 1;
1908 ast_hangup(session->channel);
1909
1910 if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS
1911 && packet) {
1913 }
1914 } else {
1915 ast_debug(3, "INVITE with Replaces in-dialog on channel '%s', hanging up\n",
1916 ast_channel_name(session->channel));
1917 ast_queue_hangup(session->channel);
1918 }
1919
1920 return 1;
1921}
1922
1923static int refer_incoming_refer_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1924{
1925 pjsip_generic_string_hdr *refer_to;
1926 char *uri;
1927 size_t uri_size;
1928 pjsip_uri *target;
1929 pjsip_sip_uri *target_uri;
1931 pjsip_param *replaces;
1932 int response;
1933
1934 static const pj_str_t str_refer_to = { "Refer-To", 8 };
1935 static const pj_str_t str_refer_to_s = { "r", 1 };
1936 static const pj_str_t str_replaces = { "Replaces", 8 };
1937
1938 if (!session->channel) {
1939 /* No channel to refer. Likely because the call was just hung up. */
1940 pjsip_dlg_respond(session->inv_session->dlg, rdata, 404, NULL, NULL, NULL);
1941 ast_debug(3, "Received a REFER on a session with no channel from endpoint '%s'.\n",
1943 return 0;
1944 }
1945
1946 if (!session->endpoint->allowtransfer) {
1947 pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
1948 ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
1950 return 0;
1951 }
1952
1953 /* A Refer-To header is required */
1954 refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL);
1955 if (!refer_to) {
1956 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1957 ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
1959 return 0;
1960 }
1961
1962 /* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri
1963 * as pjsip_parse_uri require a NULL terminated uri
1964 */
1965
1966 uri_size = pj_strlen(&refer_to->hvalue) + 1;
1967 uri = ast_alloca(uri_size);
1968 ast_copy_pj_str(uri, &refer_to->hvalue, uri_size);
1969
1970 target = pjsip_parse_uri(rdata->tp_info.pool, uri, uri_size - 1, 0);
1971
1972 if (!target
1973 || (!PJSIP_URI_SCHEME_IS_SIP(target)
1974 && !PJSIP_URI_SCHEME_IS_SIPS(target))) {
1975
1976 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1977 ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n",
1978 uri, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
1979 return 0;
1980 }
1981 target_uri = pjsip_uri_get_uri(target);
1982
1983 /* Set up REFER progress subscription if requested/possible */
1984 if (refer_progress_alloc(session, rdata, &progress)) {
1985 pjsip_dlg_respond(session->inv_session->dlg, rdata, 500, NULL, NULL, NULL);
1986 ast_debug(3, "Could not set up subscription for REFER on channel '%s' from endpoint '%s'\n",
1988 return 0;
1989 }
1990
1991 replaces = pjsip_param_find(&target_uri->header_param, &str_replaces);
1992 if (!replaces) {
1993 replaces = pjsip_param_find(&target_uri->other_param, &str_replaces);
1994 }
1995
1996 /* Determine if this is handled externally or an attended or blind transfer */
1997 if (session->transferhandling_ari) {
1998 response = refer_incoming_ari_request(session, rdata, target_uri, replaces, progress);
1999 } else if (replaces) {
2000 response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
2001 } else {
2002 response = refer_incoming_blind_request(session, rdata, target_uri, progress);
2003 }
2004
2005 if (!progress) {
2006 /* The transferer has requested no subscription, so send a final response immediately */
2007 pjsip_tx_data *tdata;
2008 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
2009 const pj_str_t str_false = { "false", 5 };
2010 pjsip_hdr *hdr;
2011
2012 ast_debug(3, "Progress monitoring not requested for REFER on channel '%s' from endpoint '%s', sending immediate response of '%d'\n",
2013 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), response);
2014
2015 if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, response, NULL, &tdata) != PJ_SUCCESS) {
2016 pjsip_dlg_respond(session->inv_session->dlg, rdata, response, NULL, NULL, NULL);
2017 return 0;
2018 }
2019
2020 hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
2021 pjsip_msg_add_hdr(tdata->msg, hdr);
2022
2023 pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2024 } else if (response != 200) {
2025 /* Since this failed we can send a final NOTIFY now and terminate the subscription */
2026 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
2027
2028 if (notification) {
2029 /* The refer_progress_notify function will call ao2_cleanup on this for us */
2030 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
2031 ao2_cleanup(notification);
2032 }
2033 }
2034 }
2035
2036 return 0;
2037}
2038
2039static int refer_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
2040{
2041 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
2043 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_invite_method)) {
2045 } else {
2046 return 0;
2047 }
2048}
2049
2050/*!
2051 * \brief Use the value of a channel variable as the value of a SIP header
2052 *
2053 * This looks up a variable name on a channel, then takes that value and adds
2054 * it to an outgoing SIP request. If the header already exists on the message,
2055 * then no action is taken.
2056 *
2057 * \pre chan is locked.
2058 *
2059 * \param chan The channel on which to find the variable.
2060 * \param var_name The name of the channel variable to use.
2061 * \param header_name The name of the SIP header to add to the outgoing message.
2062 * \param tdata The outgoing SIP message on which to add the header
2063 */
2064static void add_header_from_channel_var(struct ast_channel *chan, const char *var_name, const char *header_name, pjsip_tx_data *tdata)
2065{
2066 const char *var_value;
2067 pj_str_t pj_header_name;
2068 pjsip_hdr *header;
2069
2070 var_value = pbx_builtin_getvar_helper(chan, var_name);
2071 if (ast_strlen_zero(var_value)) {
2072 return;
2073 }
2074
2075 pj_cstr(&pj_header_name, header_name);
2076 header = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_header_name, NULL);
2077 if (header) {
2078 return;
2079 }
2080 ast_sip_add_header(tdata, header_name, var_value);
2081}
2082
2083static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
2084{
2085 if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method)
2086 || !session->channel
2087 || session->inv_session->state != PJSIP_INV_STATE_NULL) {
2088 return;
2089 }
2090
2091 ast_channel_lock(session->channel);
2092 add_header_from_channel_var(session->channel, "SIPREPLACESHDR", "Replaces", tdata);
2093 add_header_from_channel_var(session->channel, "SIPREFERREDBYHDR", "Referred-By", tdata);
2094 ast_channel_unlock(session->channel);
2095}
2096
2099 .incoming_request = refer_incoming_request,
2100 .outgoing_request = refer_outgoing_request,
2101};
2102
2103static int load_module(void)
2104{
2105 const pj_str_t str_norefersub = { "norefersub", 10 };
2106
2107 pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint());
2108 pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint());
2109
2110 if (ast_sip_get_norefersub()) {
2111 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub);
2112 }
2113
2116 }
2117
2119 if (!refer_serializer) {
2122 }
2123
2127
2129
2131}
2132
2133static int unload_module(void)
2134{
2139
2140 return 0;
2141}
2142
2143AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Blind and Attended Transfer Support",
2144 .support_level = AST_MODULE_SUPPORT_CORE,
2145 .load = load_module,
2146 .unload = unload_module,
2147 .load_pri = AST_MODPRI_APP_DEPEND,
2148 .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:4477
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:4494
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:4746
Internal Asterisk hangup causes.
#define AST_CAUSE_FAILURE
Definition: causes.h:150
enum cc_state state
Definition: ccss.c:399
const char * ast_channel_name(const struct ast_channel *chan)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2570
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1169
#define ast_channel_lock(chan)
Definition: channel.h:2970
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2995
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:1158
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:10692
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1243
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3006
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3017
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1481
#define ast_channel_unlock(chan)
Definition: channel.h:2971
#define AST_MAX_EXTENSION
Definition: channel.h:134
int ast_raw_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2719
@ AST_STATE_RING
Definition: channelstate.h:40
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7407
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
FrameHook Architecture.
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
Definition: framehook.c:132
ast_framehook_event
These are the types of events that the framehook's event callback can receive.
Definition: framehook.h:151
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
struct ast_sip_endpoint * ast_sip_dialog_get_endpoint(pjsip_dialog *dlg)
Get the endpoint associated with this dialog.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2094
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
int ast_sip_thread_is_servant(void)
Determine if the current thread is a SIP servant thread.
Definition: res_pjsip.c:2310
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:2165
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:2179
static char prefix[MAX_PREFIX]
Definition: http.c:144
ast_control_transfer
@ AST_TRANSFER_FAILED
@ AST_TRANSFER_UNAVAILABLE
@ AST_TRANSFER_SUCCESS
@ AST_TRANSFER_PROGRESS
@ AST_TRANSFER_INVALID
@ AST_FRAME_VOICE
@ AST_FRAME_CONTROL
@ AST_CONTROL_RING
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_BUSY
@ AST_CONTROL_PROCEEDING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ 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:4190
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
struct stasis_forward * sub
Definition: res_corosync.c:240
struct ast_sip_endpoint * ast_sip_get_endpoint(const char *to, int get_default_outbound, char **uri)
Retrieves an endpoint and URI from the "to" string.
Definition: res_pjsip.c:3249
unsigned int ast_sip_get_norefersub(void)
Retrieve the global setting 'norefersub'.
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:133
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:117
pjsip_dialog * ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user)
General purpose method for creating a UAC dialog with an endpoint.
Definition: res_pjsip.c:964
int ast_sip_rewrite_uri_to_local(pjsip_sip_uri *uri, pjsip_tx_data *tdata)
Replace domain and port of SIP URI to point to (external) signaling address of this Asterisk instance...
Definition: res_pjsip.c:605
int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, pjsip_tx_data *tdata, pjsip_tx_data **new_request)
Create a response to an authentication challenge.
Definition: res_pjsip.c:214
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3504
int ast_sip_update_from(pjsip_tx_data *tdata, char *from)
Overwrite fields in the outbound 'From' header.
Definition: res_pjsip.c:3383
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition: res_pjsip.h:3339
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, void *token, void(*callback)(void *token, pjsip_event *e))
General purpose method for sending a SIP request.
Definition: res_pjsip.c:1979
int ast_sip_update_to_uri(pjsip_tx_data *tdata, const char *to)
Replace the To URI in the tdata with the supplied one.
Definition: res_pjsip.c:3323
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition: res_pjsip.c:2008
#define MAX_RX_CHALLENGES
Definition: res_pjsip.h: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 int invite_replaces(void *data)
Task for invite replaces.
static void refer_out_of_dialog_destroy(void *obj)
Destructor for REFER out of dialog structure.
static int session_end_if_deferred_task(void *data)
static int load_module(void)
static 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.
Definition: pjsip_session.c:63
int ast_sip_session_defer_termination(struct ast_sip_session *session)
Defer local termination of a session until remote side terminates, or an amount of time passes.
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
#define NULL
Definition: resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1050
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1104
#define stasis_subscribe_pool(topic, callback, data)
Definition: stasis.h:680
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1201
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:998
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:742
Blob of data associated with a bridge.
struct ast_channel_snapshot * channel
Structure that contains information about a bridge.
Definition: bridge.h: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.
union ast_frame::@228 data
struct ast_frame_subclass subclass
enum ast_frame_type frametype
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:1051
A supplement to SIP message processing.
enum ast_sip_supplement_priority priority
A structure describing a SIP session.
struct ast_channel * channel
struct ast_taskprocessor * serializer
Support for dynamic strings.
Definition: strings.h:623
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
Definition: astman.c:222
Structure used to retrieve channel from another session.
struct ast_sip_session * session
Session we want the channel from.
struct ast_channel * channel
Channel from the session (with reference)
struct ast_bridge * bridge
Bridge the channel is in.
Definition: dsp.c:117
Structure for attended transfer task.
struct ast_sip_session * transferer
Transferer session.
struct ast_sip_session * transferer_second
Second transferer session.
struct refer_progress * progress
Optional refer progress structure.
struct ast_channel * transferer_chan
Transferer channel.
Structure for blind transfer callback details.
pjsip_replaces_hdr * replaces
Optional Replaces header.
pjsip_rx_data * rdata
REFER message.
struct refer_progress * progress
Optional progress structure.
unsigned int attended
Attended transfer flag.
const char * context
Context being used for transfer.
pjsip_sip_uri * refer_to
Optional Refer-To header.
char * destination
struct ast_refer * refer
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).
Definition: taskprocessor.h:61
FILE * out
Definition: utils/frame.c:33
int error(const char *format,...)
Definition: utils/frame.c:999
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
Definition: utils.c:781
#define ARRAY_LEN(a)
Definition: utils.h:666
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680