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