Asterisk - The Open Source Telephony Project GIT-master-70eff7f
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 }
308 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
309 }
310
311 chan = ast_channel_get_by_name(progress->transferee);
312 if (!chan) {
313 /* The channel is already gone */
314 return;
315 }
316
317 ast_channel_lock(chan);
318 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as it has joined a bridge\n",
319 ast_channel_name(chan));
320 ast_framehook_detach(chan, progress->framehook);
321 ast_channel_unlock(chan);
322
323 ast_channel_unref(chan);
324}
325
326/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer */
327static struct ast_frame *refer_progress_framehook(struct ast_channel *chan, struct ast_frame *f,
328 enum ast_framehook_event event, void *data)
329{
330 struct refer_progress *progress = data;
331 struct refer_progress_notification *notification = NULL;
332
333 /* We only care about frames *to* the channel */
334 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
335 return f;
336 }
337
338 /* If the completed flag hasn't been raised, skip this pass. */
339 if (!progress->transfer_data->completed) {
340 return f;
341 }
342
343 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
344 if (f->frametype == AST_FRAME_VOICE && !progress->subclass) {
345 /* Media is passing without progress, this means the call has been answered */
346 progress->subclass = AST_CONTROL_ANSWER;
347 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
348 } else if (f->frametype == AST_FRAME_CONTROL) {
349 /* Based on the control frame being written we can send a NOTIFY advising of the progress */
351 /* Don't set progress->subclass; an ANSWER can still follow */
352 notification = refer_progress_notification_alloc(progress, 180, PJSIP_EVSUB_STATE_ACTIVE);
353 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
354 progress->subclass = f->subclass.integer;
355 notification = refer_progress_notification_alloc(progress, 486, PJSIP_EVSUB_STATE_TERMINATED);
356 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
357 progress->subclass = f->subclass.integer;
358 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
359 } else if (f->subclass.integer == AST_CONTROL_PROGRESS) {
360 /* Don't set progress->subclass; an ANSWER can still follow */
361 notification = refer_progress_notification_alloc(progress, 183, PJSIP_EVSUB_STATE_ACTIVE);
362 } else if (f->subclass.integer == AST_CONTROL_PROCEEDING) {
363 /* Don't set progress->subclass; an ANSWER can still follow */
364 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
365 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
366 progress->subclass = f->subclass.integer;
367 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
368 }
369 }
370
371 /* If a notification is due to be sent push it to the taskpool */
372 if (notification) {
373 /* If the subscription is being terminated we don't need the frame hook any longer */
374 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
375 ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
376 ast_channel_name(chan));
377 ast_framehook_detach(chan, progress->framehook);
378 }
379
380 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
381 ao2_cleanup(notification);
382 }
383 }
384
385 return f;
386}
387
388/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer. Used for the ari-only mode */
390{
391 struct refer_progress *progress = data;
392 struct refer_progress_notification *notification = NULL;
393 SCOPE_ENTER(3, "%s\n", ast_channel_name(chan));
394
395 /* We only care about frames *to* the channel */
396 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
397 SCOPE_EXIT_RTN_VALUE(f, "%s: Not EVENT_WRITE\n", ast_channel_name(chan));
398 }
399
400 /* Determine the state of the REFER based on the control frames (or voice frames) passing */
403 && f->datalen >= sizeof(enum ast_control_transfer)) {
405 ast_trace(-1, "%s message: %d\n", ast_channel_name(chan), *message);
406 switch (*message) {
408 notification = refer_progress_notification_alloc(progress, 603, PJSIP_EVSUB_STATE_TERMINATED);
409 break;
411 notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
412 break;
414 notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
415 break;
417 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
418 break;
420 break;
421 }
422 progress->ari_state->last_response = *message;
423 }
424
425 /* If a notification is due to be sent push it to the taskpool */
426 if (notification) {
427 /* If the subscription is being terminated we don't need the frame hook any longer */
428 if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
429 ast_trace(-1, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
430 ast_channel_name(chan));
431 ast_framehook_detach(chan, progress->framehook);
432 }
433
434 /*
435 * If the referer specified "Refer-Sub: false", we can call refer_progress_notify()
436 * directly without pushing a task because it won't be doing any pjproject wotk.
437 * All it will do is send an ARI event.
438 */
439 if (notification->progress->no_refer_sub) {
440 refer_progress_notify(notification);
441 SCOPE_EXIT_RTN_VALUE(f, "%s: done ari no refer sub\n",
442 progress->ari_state ? ast_channel_name(progress->ari_state->transferer_chan) : "????");
443 }
444
445 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
446 ao2_cleanup(notification);
447 }
448 } else {
449 SCOPE_EXIT_RTN_VALUE(f, "%s: Not a transfer event\n", ast_channel_name(chan));
450 }
451
452 SCOPE_EXIT_RTN_VALUE(f, "%s: done\n", ast_channel_name(chan));
453}
454
455/*! \brief Destroy callback for monitoring framehook */
456static void refer_progress_framehook_destroy(void *data)
457{
458 struct refer_progress *progress = data;
459 struct refer_progress_notification *notification = NULL;
460 SCOPE_ENTER(3, "%p\n", progress);
461
462 /*
463 * If the referer didn't request the subscription be suppressed, we need to do
464 * a final notification.
465 */
466 if (!progress->no_refer_sub) {
467 notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
468 if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
469 ao2_cleanup(notification);
470 }
471 }
472
473 if (progress->bridge_sub) {
474 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
475 }
476
478 SCOPE_EXIT_RTN("%p\n", progress);
479}
480
481/*!
482 * \brief Callback for REFER subscription state changes
483 * \see refer_progress_notify
484 *
485 * The documentation attached to refer_progress_notify has more
486 * information about the locking issues with cleaning up
487 * the subscription.
488 *
489 * \note pjproject holds the dialog lock while calling this function.
490 */
491static void refer_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
492{
493 struct refer_progress *progress = pjsip_evsub_get_mod_data(sub, refer_progress_module.id);
494
495 /*
496 * If being destroyed, remove the progress object from the subscription
497 * and release the reference it had.
498 */
499 if (progress && (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)) {
500 pjsip_evsub_set_mod_data(progress->sub, refer_progress_module.id, NULL);
501 progress->sub = NULL;
503 }
504}
505
506/*! \brief Callback structure for subscription */
507static pjsip_evsub_user refer_progress_evsub_cb = {
508 .on_evsub_state = refer_progress_on_evsub_state,
509};
510
511static int dlg_releaser_task(void *data) {
512 pjsip_dlg_dec_session((pjsip_dialog *)data, &refer_progress_module);
513 return 0;
514}
515
516/*! \brief Destructor for REFER progress sutrcture */
517static void refer_progress_destroy(void *obj)
518{
519 struct refer_progress *progress = obj;
520 SCOPE_ENTER(3, "%p\n", progress);
521
522 if (progress->bridge_sub) {
523 progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
524 }
525
526 if (progress->dlg) {
527 /*
528 * Although the dlg session count was incremented in a pjsip servant
529 * thread, there's no guarantee that the last thread to unref this progress
530 * object was one. Before we decrement, we need to make sure that this
531 * is either a servant thread or that we push the decrement to a
532 * serializer that is one.
533 *
534 * Because pjsip_dlg_dec_session requires the dialog lock, we don't want
535 * to wait on the task to complete if we had to push it to a serializer.
536 */
538 pjsip_dlg_dec_session(progress->dlg, &refer_progress_module);
539 } else {
541 }
542 }
543
544 ao2_cleanup(progress->transfer_data);
545 ao2_cleanup(progress->ari_state);
546
547 ast_free(progress->transferee);
549 SCOPE_EXIT_RTN("%p\n", progress);
550}
551
552/*! \brief Internal helper function which sets up a refer progress structure if needed */
553static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata, struct refer_progress **progress)
554{
555 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
556 pjsip_generic_string_hdr *refer_sub = NULL;
557 const pj_str_t str_true = { "true", 4 };
558 pjsip_hdr hdr_list;
559 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
560 int no_refer_sub = 0;
561 SCOPE_ENTER(3, "%s\n", ast_channel_name(session->channel));
562
563 *progress = NULL;
564
565 /* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */
566 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
567 if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4))) {
568 no_refer_sub = 1;
569 }
570
571 if (!(*progress = ao2_alloc(sizeof(struct refer_progress), refer_progress_destroy))) {
572 SCOPE_EXIT_RTN_VALUE(-1, "%s: done: %d\n", ast_channel_name(session->channel), -1);
573 }
574
575 (*progress)->no_refer_sub = no_refer_sub;
576
577 ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
579
580 (*progress)->refer_blind_progress = session->endpoint->refer_blind_progress;
581
582 (*progress)->framehook = -1;
583
584 /* Create name with seq number appended. */
585 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/refer/%s",
587
588 if (!((*progress)->serializer = ast_sip_create_serializer(tps_name))) {
589 goto error;
590 }
591
592 /*
593 * If the referer request the subscription be suppressed, we can stop here.
594 */
595 if ((*progress)->no_refer_sub) {
596 SCOPE_EXIT_RTN_VALUE(0, "%s: done no refer sub: %d\n", ast_channel_name(session->channel), 0);
597 }
598
599 /* Create the implicit subscription for monitoring of this transfer */
600 if (pjsip_xfer_create_uas(session->inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
601 goto error;
602 }
603
604 /* To prevent a potential deadlock we need the dialog so we can lock/unlock */
605 (*progress)->dlg = session->inv_session->dlg;
606 /* We also need to make sure it stays around until we're done with it */
607 pjsip_dlg_inc_session((*progress)->dlg, &refer_progress_module);
608
609 /* Associate the REFER progress structure with the subscription */
610 ao2_ref(*progress, +1);
611 pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
612
613 pj_list_init(&hdr_list);
614 if (refer_sub) {
615 pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->inv_session->dlg->pool, &str_refer_sub, &str_true);
616
617 pj_list_push_back(&hdr_list, hdr);
618 }
619
620 /* Accept the REFER request */
621 ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress);
622 pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
623
624 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
625
626error:
628 *progress = NULL;
629 SCOPE_EXIT_RTN_VALUE(-1, "%s: done: %d\n", ast_channel_name(session->channel), -1);
630}
631
632/*! \brief Structure for attended transfer task */
634 /*! \brief Transferer session */
636 /*! \brief Transferer channel */
638 /*! \brief Second transferer session */
640 /*! \brief Optional refer progress structure */
642};
643
644/*! \brief Destructor for attended transfer task */
645static void refer_attended_destroy(void *obj)
646{
647 struct refer_attended *attended = obj;
648
649 ao2_cleanup(attended->transferer);
652 ao2_cleanup(attended->progress);
653}
654
655/*! \brief Allocator for attended transfer task */
658 struct refer_progress *progress)
659{
660 struct refer_attended *attended;
661
662 attended = ao2_alloc_options(sizeof(*attended), refer_attended_destroy,
664 if (!attended) {
665 return NULL;
666 }
667
668 ao2_ref(transferer, +1);
669 attended->transferer = transferer;
674
675 if (progress) {
676 ao2_ref(progress, +1);
677 attended->progress = progress;
678 }
679
680 return attended;
681}
682
683static int session_end_if_deferred_task(void *data)
684{
685 struct ast_sip_session *session = data;
686
688 ao2_ref(session, -1);
689 return 0;
690}
691
701
702/*!
703 * \internal
704 * \brief Convert transfer enum to SIP response code.
705 * \since 13.3.0
706 *
707 * \param xfer_code Core transfer function enum result.
708 *
709 * \return SIP response code
710 */
712{
713 int response;
714
715 response = 503;
716 switch (xfer_code) {
718 response = 400;
719 break;
721 response = 403;
722 break;
724 response = 500;
725 break;
727 response = 200;
728 break;
729 }
730 return response;
731}
732
733/*! \brief Task for attended transfer executed by attended->transferer_second serializer */
734static int refer_attended_task(void *data)
735{
736 struct refer_attended *attended = data;
737 int response;
738 int (*task_cb)(void *data);
739
740 if (attended->transferer_second->channel) {
741 ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
744
746 attended->transferer_chan,
747 attended->transferer_second->channel));
748
749 ast_debug(3, "Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
752 response);
753 } else {
754 ast_debug(3, "Received REFER request on channel '%s' but other channel has gone.\n",
756 response = 603;
757 }
758
759 if (attended->progress) {
760 struct refer_progress_notification *notification;
761
762 notification = refer_progress_notification_alloc(attended->progress, response,
763 PJSIP_EVSUB_STATE_TERMINATED);
764 if (notification) {
765 if (ast_sip_push_task(attended->progress->serializer, refer_progress_notify, notification)) {
766 ao2_cleanup(notification);
767 }
768 }
769 }
770
771 if (response == 200) {
773 } else {
775 }
777 task_cb, attended->transferer)) {
778 /* Gave the ref to the pushed task. */
779 attended->transferer = NULL;
780 } else {
781 /* Do this anyway even though it is the wrong serializer. */
783 }
784
785 ao2_ref(attended, -1);
786 return 0;
787}
788
789/*! \brief Structure for blind transfer callback details */
791 /*! \brief Context being used for transfer */
792 const char *context;
793 /*! \brief Optional progress structure */
795 /*! \brief REFER message */
796 pjsip_rx_data *rdata;
797 /*! \brief Optional Replaces header */
798 pjsip_replaces_hdr *replaces;
799 /*! \brief Optional Refer-To header */
800 pjsip_sip_uri *refer_to;
801 /*! \brief Attended transfer flag */
802 unsigned int attended:1;
803};
804
805/*! \brief Blind transfer callback function */
806static void refer_blind_callback(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
807 enum ast_transfer_type transfer_type)
808{
809 struct refer_blind *refer = user_data_wrapper->data;
810 pjsip_generic_string_hdr *referred_by;
811
812 static const pj_str_t str_referred_by = { "Referred-By", 11 };
813 static const pj_str_t str_referred_by_s = { "b", 1 };
814 const char *get_xfrdata;
815
816 pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
817
818 if (refer->progress && !refer->attended && !refer->progress->refer_blind_progress) {
819 /* If blind transfer and endpoint doesn't want to receive all the progress details */
821 PJSIP_EVSUB_STATE_TERMINATED);
822
823 if (notification) {
824 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
825 ao2_cleanup(notification);
826 }
827 }
828 } else if (refer->progress) {
829 /* If attended transfer and progress monitoring is being done attach a frame hook so we can monitor it */
830 struct ast_framehook_interface hook = {
832 .event_cb = refer_progress_framehook,
834 .data = refer->progress,
835 .disable_inheritance = 1,
836 };
837
839 if (!refer->progress->transferee) {
841 PJSIP_EVSUB_STATE_TERMINATED);
842
843 ast_log(LOG_WARNING, "Could not copy channel name '%s' during transfer - assuming success\n",
844 ast_channel_name(chan));
845
846 if (notification) {
847 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
848 ao2_cleanup(notification);
849 }
850 }
851 }
852
853 /* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
854 ao2_ref(user_data_wrapper, +1);
855 refer->progress->transfer_data = user_data_wrapper;
856
857 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
858 ao2_ref(refer->progress, +1);
859
860 /* If we can't attach a frame hook for whatever reason send a notification of success immediately */
861 ast_channel_lock(chan);
862 refer->progress->framehook = ast_framehook_attach(chan, &hook);
863 ast_channel_unlock(chan);
864 if (refer->progress->framehook < 0) {
866 PJSIP_EVSUB_STATE_TERMINATED);
867
868 ast_log(LOG_WARNING, "Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
869 ast_channel_name(chan));
870
871 if (notification) {
872 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
873 ao2_cleanup(notification);
874 }
875 }
876
877 ao2_cleanup(refer->progress);
878 }
879
880 /* We need to bump the reference count for the stasis subscription */
881 ao2_ref(refer->progress, +1);
882 /* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
883 * detect if the transfer target has answered the call
884 */
886 if (!refer->progress->bridge_sub) {
888 PJSIP_EVSUB_STATE_TERMINATED);
889
890 ast_log(LOG_WARNING, "Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success\n",
891 ast_channel_name(chan));
892
893 if (notification) {
894 if (ast_sip_push_task(refer->progress->serializer, refer_progress_notify, notification)) {
895 ao2_cleanup(notification);
896 }
897 }
898
899 ast_channel_lock(chan);
901 ast_channel_unlock(chan);
902
903 ao2_cleanup(refer->progress);
904 } else {
908 }
909 }
910
911 pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL));
912
913 ast_channel_lock(chan);
914 if ((get_xfrdata = pbx_builtin_getvar_helper(chan, "GET_TRANSFERRER_DATA"))) {
915 get_xfrdata = ast_strdupa(get_xfrdata);
916 }
917 ast_channel_unlock(chan);
918 if (!ast_strlen_zero(get_xfrdata)) {
919 const pjsip_msg * msg = refer->rdata->msg_info.msg;
920 const struct pjsip_hdr *end = &msg->hdr;
921 struct pjsip_hdr *hdr = end->next;
922 struct ast_str *pbxvar = ast_str_create(64); /* initial buffer for variable name, extended on demand */
923 char buf[4096]; /* should be enough for one header value */
924 const char *prefix = get_xfrdata;
925
926 /* The '*' alone matches all headers. */
927 if (!strcmp(prefix, "*")) {
928 prefix = "";
929 }
930 if (pbxvar) {
931 for (; hdr != end; hdr = hdr->next) {
932 if (!pj_strnicmp2(&hdr->name, prefix, strlen(prefix))) {
933 const int hdr_name_strlen = pj_strlen(&hdr->name);
934 const int hdr_name_bytes = hdr_name_strlen + 1; /* +1 for string NULL terminator */
935 char hdr_name[hdr_name_bytes];
936 int len;
937 char *value_str;
938
939 ast_copy_pj_str(hdr_name, &hdr->name, hdr_name_bytes);
940 len = pjsip_hdr_print_on(hdr, buf, sizeof(buf) - 1);
941 if (len < 0) {
942 /* ignore too long headers */
943 ast_log(LOG_WARNING, "Could not store header '%s' from transfer on channel '%s' - too long text\n", hdr_name, ast_channel_name(chan));
944 continue;
945 }
946 buf[len] = '\0';
947
948 /* Get value - remove header name (before ':') from buf and trim blanks. */
949 value_str = strchr(buf, ':');
950 if (!value_str) {
951 /* Ignore header without value */
952 continue;
953 }
954 value_str = ast_strip(value_str + 1); /* +1 to get string right after the ':' delimiter (i.e. header value) */
955
956 ast_str_set(&pbxvar, -1, "~HASH~TRANSFER_DATA~%.*s~", hdr_name_strlen, hdr_name);
957 pbx_builtin_setvar_helper(chan, ast_str_buffer(pbxvar), value_str);
958 ast_debug(5, "On channel '%s' set TRANSFER_DATA variable '%s' to value '%s' \n", ast_channel_name(chan), hdr_name, value_str);
959 }
960 }
961 ast_free(pbxvar);
962 } else {
963 ast_log(LOG_ERROR, "Channel '%s' failed to allocate buffer for TRANSFER_DATA variable\n", ast_channel_name(chan));
964 }
965 }
966
967 referred_by = pjsip_msg_find_hdr_by_names(refer->rdata->msg_info.msg,
968 &str_referred_by, &str_referred_by_s, NULL);
969 if (referred_by) {
970 size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
971 char *uri = ast_alloca(uri_size);
972
973 ast_copy_pj_str(uri, &referred_by->hvalue, uri_size);
974 pbx_builtin_setvar_helper(chan, "__SIPREFERREDBYHDR", S_OR(uri, NULL));
975 } else {
976 pbx_builtin_setvar_helper(chan, "SIPREFERREDBYHDR", NULL);
977 }
978
979 if (refer->replaces) {
980 char replaces[512];
981 char *replaces_val = NULL;
982 int len;
983
984 len = pjsip_hdr_print_on(refer->replaces, replaces, sizeof(replaces) - 1);
985 if (len != -1) {
986 /* pjsip_hdr_print_on does not NULL terminate the buffer */
987 replaces[len] = '\0';
988 replaces_val = replaces + sizeof("Replaces:");
989 }
990 pbx_builtin_setvar_helper(chan, "__SIPREPLACESHDR", replaces_val);
991 } else {
992 pbx_builtin_setvar_helper(chan, "SIPREPLACESHDR", NULL);
993 }
994
995 if (refer->refer_to) {
996 char refer_to[PJSIP_MAX_URL_SIZE];
997
998 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->refer_to, refer_to, sizeof(refer_to));
999 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", S_OR(refer_to, NULL));
1000 } else {
1001 pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", NULL);
1002 }
1003}
1004
1005/*!
1006 * \internal
1007 * \brief Set the passed in context variable to the determined transfer context.
1008 * \since 13.3.0
1009 *
1010 * \param context Set to the determined transfer context.
1011 * \param session INVITE dialog SIP session.
1012 */
1013#define DETERMINE_TRANSFER_CONTEXT(context, session) \
1014 do { \
1015 ast_channel_lock((session)->channel); \
1016 context = pbx_builtin_getvar_helper((session)->channel, "TRANSFER_CONTEXT"); \
1017 if (ast_strlen_zero(context)) { \
1018 context = (session)->endpoint->context; \
1019 } else { \
1020 context = ast_strdupa(context); \
1021 } \
1022 ast_channel_unlock((session)->channel); \
1023 } while (0) \
1024
1025struct refer_data {
1028 char *from;
1031};
1032
1033static void refer_data_destroy(void *obj)
1034{
1035 struct refer_data *rdata = obj;
1036
1037 ast_free(rdata->destination);
1038 ast_free(rdata->from);
1039 ast_free(rdata->refer_to);
1040
1041 ast_refer_destroy(rdata->refer);
1042}
1043
1044static struct refer_data *refer_data_create(const struct ast_refer *refer)
1045{
1046 char *uri_params;
1047 const char *destination;
1049
1050 if (!rdata) {
1051 return NULL;
1052 }
1053
1054 /* typecast to suppress const warning */
1055 rdata->refer = ast_refer_ref((struct ast_refer *) refer);
1057
1058 /* To starts with 'pjsip:' which needs to be removed. */
1059 if (!(destination = strchr(destination, ':'))) {
1060 goto failure;
1061 }
1062 ++destination;/* Now skip the ':' */
1063
1065 if (!rdata->destination) {
1066 goto failure;
1067 }
1068
1070 if (!rdata->from) {
1071 goto failure;
1072 }
1073
1075 if (!rdata->refer_to) {
1076 goto failure;
1077 }
1079
1080 /*
1081 * Sometimes from URI can contain URI parameters, so remove them.
1082 *
1083 * sip:user;user-options@domain;uri-parameters
1084 */
1085 uri_params = strchr(rdata->from, '@');
1086 if (uri_params && (uri_params = strchr(uri_params, ';'))) {
1087 *uri_params = '\0';
1088 }
1089 return rdata;
1090
1091failure:
1092 ao2_cleanup(rdata);
1093 return NULL;
1094}
1095
1096/*!
1097 * \internal
1098 * \brief Checks if the given refer var name should be blocked.
1099 *
1100 * \details Some headers are not allowed to be overridden by the user.
1101 * Determine if the given var header name from the user is blocked for
1102 * an outgoing REFER.
1103 *
1104 * \param name name of header to see if it is blocked.
1105 *
1106 * \retval TRUE if the given header is blocked.
1107 */
1108static int is_refer_var_blocked(const char *name)
1109{
1110 int i;
1111
1112 /* Don't block the Max-Forwards header because the user can override it */
1113 static const char *hdr[] = {
1114 "To",
1115 "From",
1116 "Via",
1117 "Route",
1118 "Contact",
1119 "Call-ID",
1120 "CSeq",
1121 "Allow",
1122 "Content-Length",
1123 "Content-Type",
1124 "Request-URI",
1125 };
1126
1127 for (i = 0; i < ARRAY_LEN(hdr); ++i) {
1128 if (!strcasecmp(name, hdr[i])) {
1129 /* Block addition of this header. */
1130 return 1;
1131 }
1132 }
1133 return 0;
1134}
1135
1136/*!
1137 * \internal
1138 * \brief Copies any other refer vars over to the request headers.
1139 *
1140 * \param refer The refer structure to copy headers from
1141 * \param tdata The SIP transmission data
1142 */
1143static enum pjsip_status_code vars_to_headers(const struct ast_refer *refer, pjsip_tx_data *tdata)
1144{
1145 const char *name;
1146 const char *value;
1148
1149 for (iter = ast_refer_var_iterator_init(refer);
1152 if (!is_refer_var_blocked(name)) {
1153 ast_sip_add_header(tdata, name, value);
1154 }
1155 }
1157
1158 return PJSIP_SC_OK;
1159}
1160
1165
1166/*! \brief REFER Out-of-dialog module, used to attach session data structure to subscription */
1167static pjsip_module refer_out_of_dialog_module = {
1168 .name = { "REFER Out-of-dialog Module", 26 },
1169 .id = -1,
1170 .on_tx_request = refer_on_tx_request,
1171 /* Ensure that we are called after res_pjsp_nat module and before transport priority */
1172 .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 4,
1173};
1174
1175/*! \brief Helper function which returns the name-addr of the Refer-To header or NULL */
1176static pjsip_uri *get_refer_to_uri(pjsip_tx_data *tdata)
1177{
1178 const pj_str_t REFER_TO = { "Refer-To", 8 };
1179 pjsip_generic_string_hdr *refer_to;
1180 pjsip_uri *parsed_uri;
1181
1182 if (!(refer_to = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL))
1183 || !(parsed_uri = pjsip_parse_uri(tdata->pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0))
1184 || (!PJSIP_URI_SCHEME_IS_SIP(parsed_uri) && !PJSIP_URI_SCHEME_IS_SIPS(parsed_uri))) {
1185 return NULL;
1186 }
1187
1188 return parsed_uri;
1189}
1190
1191static pj_status_t refer_on_tx_request(pjsip_tx_data *tdata) {
1192 RAII_VAR(struct ast_str *, refer_to_str, ast_str_create(PJSIP_MAX_URL_SIZE), ast_free_ptr);
1193 const pj_str_t REFER_TO = { "Refer-To", 8 };
1194 pjsip_generic_string_hdr *refer_to_hdr;
1195 pjsip_dialog *dlg;
1196 struct refer_data *refer_data;
1197 pjsip_uri *parsed_uri;
1198 pjsip_sip_uri *refer_to_uri;
1199
1200 /*
1201 * If this is a request in response to a 401/407 Unauthorized challenge, the
1202 * Refer-To URI has been rewritten already, so don't attempt to re-write it again.
1203 * Checking for presence of the Authorization header is not an ideal solution. We do this because
1204 * there exists some race condition where this dialog is not the same as the one used
1205 * to send the original request in which case we don't have the correct refer_data.
1206 */
1207 if (!refer_to_str
1208 || pjsip_msg_find_hdr(tdata->msg, PJSIP_H_AUTHORIZATION, NULL)
1209 || !(dlg = pjsip_tdata_get_dlg(tdata))
1210 || !(refer_data = pjsip_dlg_get_mod_data(dlg, refer_out_of_dialog_module.id))
1211 || !refer_data->to_self
1212 || !(parsed_uri = get_refer_to_uri(tdata))) {
1213 goto out;
1214 }
1215 refer_to_uri = pjsip_uri_get_uri(parsed_uri);
1216 ast_sip_rewrite_uri_to_local(refer_to_uri, tdata);
1217
1218 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, parsed_uri, ast_str_buffer(refer_to_str), ast_str_size(refer_to_str));
1219 refer_to_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &REFER_TO, NULL);
1220 pj_strdup2(tdata->pool, &refer_to_hdr->hvalue, ast_str_buffer(refer_to_str));
1221
1222out:
1223 return PJ_SUCCESS;
1224}
1225
1226static int refer_unreference_dialog(void *obj)
1227{
1228 struct refer_out_of_dialog *data = obj;
1229
1230 /* This is why we keep the dialog on the subscription. When the subscription
1231 * is destroyed, there is no guarantee that the underlying dialog is ready
1232 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1233 * either. The dialog could be destroyed before our subscription is. We fix
1234 * this problem by keeping a reference to the dialog until it is time to
1235 * destroy the subscription.
1236 */
1237 pjsip_dlg_dec_session(data->dlg, &refer_out_of_dialog_module);
1238 data->dlg = NULL;
1239
1240 return 0;
1241}
1242/*! \brief Destructor for REFER out of dialog structure */
1243static void refer_out_of_dialog_destroy(void *obj) {
1244 struct refer_out_of_dialog *data = obj;
1245
1246 if (data->dlg) {
1247 /* ast_sip_push_task_wait_servant should not be called in a destructor,
1248 * however in this case it seems to be fine.
1249 */
1251 }
1252}
1253
1254/*!
1255 * \internal
1256 * \brief Callback function to report status of implicit REFER-NOTIFY subscription.
1257 *
1258 * This function will be called on any state change in the REFER-NOTIFY subscription.
1259 * Its primary purpose is to report SUCCESS/FAILURE of a refer initiated via
1260 * \ref refer_send as well as to terminate the subscription, if necessary.
1261 */
1262static void refer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
1263{
1264 pjsip_tx_data *tdata;
1265 RAII_VAR(struct ast_sip_endpoint *, endpt, NULL, ao2_cleanup);
1267 int refer_success;
1268 int res = 0;
1269
1270 if (!event) {
1271 return;
1272 }
1273
1274 refer_data = pjsip_evsub_get_mod_data(sub, refer_out_of_dialog_module.id);
1275 if (!refer_data || !refer_data->dlg) {
1276 return;
1277 }
1278
1280
1281 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
1282 /* Check if subscription is suppressed and terminate and send completion code, if so. */
1283 pjsip_rx_data *rdata;
1284 pjsip_generic_string_hdr *refer_sub;
1285 const pj_str_t REFER_SUB = { "Refer-Sub", 9 };
1286
1287 ast_debug(3, "Refer accepted by %s\n", endpt ? ast_sorcery_object_get_id(endpt) : "(unknown endpoint)");
1288
1289 /* Check if response message */
1290 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1291 rdata = event->body.tsx_state.src.rdata;
1292
1293 /* Find Refer-Sub header */
1294 refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &REFER_SUB, NULL);
1295
1296 /* Check if subscription is suppressed. If it is, the far end will not terminate it,
1297 * and the subscription will remain active until it times out. Terminating it here
1298 * eliminates the unnecessary timeout.
1299 */
1300 if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
1301 /* Since no subscription is desired, assume that call has been referred successfully
1302 * and terminate subscription.
1303 */
1304 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1305 pjsip_evsub_terminate(sub, PJ_TRUE);
1306 res = -1;
1307 }
1308 }
1309 } else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
1310 pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
1311 /* Check for NOTIFY complete or error. */
1312 pjsip_msg *msg;
1313 pjsip_msg_body *body;
1314 pjsip_status_line status_line = { .code = 0 };
1315 pj_bool_t is_last;
1316 pj_status_t status;
1317
1318 if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
1319 pjsip_rx_data *rdata;
1320 pj_str_t refer_str;
1321 pj_cstr(&refer_str, "REFER");
1322
1323 rdata = event->body.tsx_state.src.rdata;
1324 msg = rdata->msg_info.msg;
1325
1326 if (msg->type == PJSIP_RESPONSE_MSG
1327 && (event->body.tsx_state.tsx->status_code == 401
1328 || event->body.tsx_state.tsx->status_code == 407)
1329 && pj_stristr(&refer_str, &event->body.tsx_state.tsx->method.name)
1330 && ++refer_data->authentication_challenge_count < MAX_RX_CHALLENGES
1331 && endpt) {
1332
1333 if (!ast_sip_create_request_with_auth(&endpt->outbound_auths,
1334 event->body.tsx_state.src.rdata, event->body.tsx_state.tsx->last_tx, &tdata)) {
1335 /* Send authed REFER */
1337 goto out;
1338 }
1339 }
1340
1341 if (msg->type == PJSIP_REQUEST_MSG) {
1342 if (!pjsip_method_cmp(&msg->line.req.method, pjsip_get_notify_method())) {
1343 body = msg->body;
1344 if (body && !pj_stricmp2(&body->content_type.type, "message")
1345 && !pj_stricmp2(&body->content_type.subtype, "sipfrag")) {
1346 pjsip_parse_status_line((char *)body->data, body->len, &status_line);
1347 }
1348 }
1349 } else {
1350 status_line.code = msg->line.status.code;
1351 status_line.reason = msg->line.status.reason;
1352 }
1353 } else {
1354 status_line.code = 500;
1355 status_line.reason = *pjsip_get_status_text(500);
1356 }
1357
1358 is_last = (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED);
1359 /* If the status code is >= 200, the subscription is finished. */
1360 if (status_line.code >= 200 || is_last) {
1361 res = -1;
1362
1363 refer_success = status_line.code >= 200 && status_line.code < 300;
1364
1365 /* If subscription not terminated and subscription is finished (status code >= 200)
1366 * terminate it */
1367 if (!is_last) {
1368 pjsip_tx_data *tdata;
1369
1370 status = pjsip_evsub_initiate(sub, pjsip_get_subscribe_method(), 0, &tdata);
1371 if (status == PJ_SUCCESS) {
1372 pjsip_evsub_send_request(sub, tdata);
1373 }
1374 }
1375 ast_debug(3, "Refer completed: %d %.*s (%s)\n",
1376 status_line.code,
1377 (int)status_line.reason.slen, status_line.reason.ptr,
1378 refer_success ? "Success" : "Failure");
1379 }
1380 }
1381
1382out:
1383 if (res) {
1385 }
1386}
1387
1388/*!
1389 * \internal
1390 * \brief Send a REFER
1391 *
1392 * \param data The outbound refer data structure
1393 *
1394 * \return 0: success, -1: failure
1395 */
1396static int refer_send(void *data)
1397{
1398 struct refer_data *rdata = data; /* The caller holds a reference */
1399 pjsip_tx_data *tdata;
1400 pjsip_evsub *sub;
1401 pj_str_t tmp;
1402 char refer_to_str[PJSIP_MAX_URL_SIZE];
1403 char disp_name_escaped[128];
1404 struct refer_out_of_dialog *refer;
1405 struct pjsip_evsub_user xfer_cb;
1406 RAII_VAR(char *, uri, NULL, ast_free);
1407 RAII_VAR(char *, tmp_str, NULL, ast_free);
1408 RAII_VAR(char *, display_name, NULL, ast_free);
1409 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1410 RAII_VAR(struct ast_sip_endpoint *, refer_to_endpoint, NULL, ao2_cleanup);
1411
1412 endpoint = ast_sip_get_endpoint(rdata->destination, 1, &uri);
1413 if (!endpoint) {
1415 "PJSIP REFER - Could not find endpoint '%s' and no default outbound endpoint configured\n",
1416 rdata->destination);
1417 return -1;
1418 }
1419 ast_debug(3, "Request URI: %s\n", uri);
1420
1421 refer_to_endpoint = ast_sip_get_endpoint(rdata->refer_to, 0, &tmp_str);
1422 if (!tmp_str) {
1423 ast_log(LOG_WARNING, "PJSIP REFER - Refer to not a valid resource identifier or SIP URI\n");
1424 return -1;
1425 }
1426 if (!(refer = ao2_alloc(sizeof(struct refer_out_of_dialog), refer_out_of_dialog_destroy))) {
1427 ast_log(LOG_ERROR, "PJSIP REFER - Could not allocate resources.\n");
1428 return -1;
1429 }
1430 /* The dialog will be terminated in the subscription event callback
1431 * when the subscription has terminated. */
1433 refer->dlg = ast_sip_create_dialog_uac(endpoint, uri, NULL);
1434 if (!refer->dlg) {
1435 ast_log(LOG_WARNING, "PJSIP REFER - Could not create dialog\n");
1436 ao2_cleanup(refer);
1437 return -1;
1438 }
1439 ast_sip_dialog_set_endpoint(refer->dlg, endpoint);
1440
1441 pj_bzero(&xfer_cb, sizeof(xfer_cb));
1442 xfer_cb.on_evsub_state = &refer_client_on_evsub_state;
1443 if (pjsip_xfer_create_uac(refer->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
1444 ast_log(LOG_WARNING, "PJSIP REFER - Could not create uac\n");
1445 ao2_cleanup(refer);
1446 return -1;
1447 }
1448
1449 display_name = ast_refer_get_var_and_unlink(rdata->refer, "display_name");
1450 if (display_name) {
1451 ast_escape_quoted(display_name, disp_name_escaped, sizeof(disp_name_escaped));
1452 snprintf(refer_to_str, sizeof(refer_to_str), "\"%s\" <%s>", disp_name_escaped, tmp_str);
1453 } else {
1454 snprintf(refer_to_str, sizeof(refer_to_str), "%s", tmp_str);
1455 }
1456
1457 /* refer_out_of_dialog_module requires a reference to dlg
1458 * which will be released in refer_client_on_evsub_state()
1459 * when the implicit REFER subscription terminates */
1460 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, refer);
1461 if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, refer_to_str), &tdata) != PJ_SUCCESS) {
1462 ast_log(LOG_WARNING, "PJSIP REFER - Could not create request\n");
1463 goto failure;
1464 }
1465
1466 if (refer_to_endpoint && rdata->to_self) {
1467 pjsip_dlg_add_usage(refer->dlg, &refer_out_of_dialog_module, rdata);
1468 }
1469
1470 ast_sip_update_to_uri(tdata, uri);
1471 ast_sip_update_from(tdata, rdata->from);
1472
1473 /*
1474 * This copies any headers found in the refer's variables to
1475 * tdata.
1476 */
1477 vars_to_headers(rdata->refer, tdata);
1478 ast_debug(1, "Sending REFER to '%s' (via endpoint %s) from '%s'\n",
1479 rdata->destination, ast_sorcery_object_get_id(endpoint), rdata->from);
1480
1481 if (pjsip_xfer_send_request(sub, tdata) == PJ_SUCCESS) {
1482 return 0;
1483 }
1484
1485failure:
1486 ao2_cleanup(refer);
1487 pjsip_evsub_set_mod_data(sub, refer_out_of_dialog_module.id, NULL);
1488 pjsip_evsub_terminate(sub, PJ_FALSE);
1489 return -1;
1490}
1491
1492static int sip_refer_send(const struct ast_refer *refer)
1493{
1494 struct refer_data *rdata;
1495 int res;
1496
1498 ast_log(LOG_ERROR, "SIP REFER - a 'To' URI must be specified\n");
1499 return -1;
1500 }
1501
1502 rdata = refer_data_create(refer);
1503 if (!rdata) {
1504 return -1;
1505 }
1506
1508 ao2_ref(rdata, -1);
1509
1510 return res;
1511}
1512
1513static const struct ast_refer_tech refer_tech = {
1514 .name = "pjsip",
1515 .refer_send = sip_refer_send,
1516};
1517
1518static char *copy_string(struct pj_str_t *str)
1519{
1520 int len = pj_strlen(str) + 1;
1521 char *dst = ast_malloc(len);
1522 if (!dst) {
1523 return NULL;
1524 }
1525 ast_copy_pj_str(dst, str, len);
1526 return dst;
1527}
1528
1529static int add_refer_param(struct ast_refer_params *params, const char *key, struct pj_str_t *str)
1530{
1531 struct ast_refer_param param;
1532
1533 param.param_name = ast_strdup(key);
1534 if (!param.param_name) {
1535 return 0;
1536 }
1537
1538 param.param_value = copy_string(str);
1539 if (!param.param_value) {
1540 ast_free((char *) param.param_name);
1541 return 0;
1542 }
1543
1544 if (AST_VECTOR_APPEND(params, param) != 0) {
1545 ast_free((char *) param.param_name);
1546 ast_free((char *) param.param_value);
1547 return 0;
1548 }
1549 return 1;
1550}
1551
1552
1553static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
1554 pjsip_param *replaces_param, struct refer_progress *progress)
1555{
1556 int parsed_len;
1557 pjsip_replaces_hdr *replaces;
1558 pjsip_generic_string_hdr *referred_hdr;
1559
1560
1562
1563 struct ast_framehook_interface hook = {
1565 .event_cb = refer_ari_progress_framehook,
1567 .data = progress,
1568 .disable_inheritance = 1,
1569 };
1570
1571 static const pj_str_t str_referred_by = { "Referred-By", 11 };
1572 static const pj_str_t str_referred_by_s = { "b", 1 };
1573 static const pj_str_t str_replaces = { "Replaces", 8 };
1574 SCOPE_ENTER(3, "%s: progress: %p\n", ast_channel_name(session->channel), progress);
1575
1576 if (!progress) {
1577 SCOPE_EXIT_RTN_VALUE(204, "%s: done: %d\n", ast_channel_name(session->channel), 204);
1578 }
1579
1581 if (!state) {
1582 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1583 }
1584
1585 state->last_response = AST_TRANSFER_INVALID;
1586
1587 state->params = ao2_alloc(sizeof(struct ast_refer_params), refer_params_destroy);
1588 if (!state->params) {
1589 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1590 }
1591 AST_VECTOR_INIT(state->params, 0);
1592
1593
1594 ast_channel_ref(session->channel);
1595 state->transferer_chan = session->channel;
1596
1597 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1598 ast_copy_pj_str(state->exten, &target->user, sizeof(state->exten));
1599
1600 /*
1601 * We may want to match in the dialplan without any user
1602 * options getting in the way.
1603 */
1605
1606 referred_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg,
1607 &str_referred_by, &str_referred_by_s, NULL);
1608 if (referred_hdr) {
1609 state->referred_by = copy_string(&referred_hdr->hvalue);
1610 if (!state->referred_by) {
1611 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1612 }
1613 }
1614
1615 if (replaces_param) {
1616 pjsip_dialog *dlg;
1617 pj_str_t replaces_content = { 0, };
1618 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1619
1620 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1621 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1622 pj_strlen(&replaces_content), &parsed_len))) {
1623 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1625 SCOPE_EXIT_RTN_VALUE(400, "%s: done: %d\n", ast_channel_name(session->channel), 400);
1626 }
1627
1628 dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE);
1629 if (dlg) {
1630 state->other_session = ast_sip_dialog_get_session(dlg);
1631 pjsip_dlg_dec_lock(dlg);
1632 }
1633
1634 state->protocol_id = copy_string(&replaces->call_id);
1635 if (!state->protocol_id) {
1636 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1637 }
1638
1639 if (!add_refer_param(state->params, "from", &replaces->from_tag)) {
1640 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1641 }
1642
1643 if (!add_refer_param(state->params, "to", &replaces->to_tag)) {
1644 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1645 }
1646 }
1647
1648 ao2_ref(session, +1);
1649 state->transferer = session;
1650
1651
1652 /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
1653 ao2_ref(progress, +1);
1654 ast_channel_lock(session->channel);
1655 progress->framehook = ast_framehook_attach(session->channel, &hook);
1656 ast_channel_unlock(session->channel);
1657
1658 if (progress->framehook < 0) {
1660 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1661 }
1662
1663 if (ari_notify(state)) {
1664 ast_channel_lock(session->channel);
1665 ast_framehook_detach(session->channel, progress->framehook);
1666 progress->framehook = -1;
1668 ast_channel_unlock(session->channel);
1669 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1670 }
1671
1672 /* Transfer ownership to the progress */
1673 progress->ari_state = state;
1674 state = NULL;
1675 SCOPE_EXIT_RTN_VALUE(200, "%s: done: %d\n", ast_channel_name(session->channel), 200);
1676}
1677
1678static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri,
1679 pjsip_param *replaces_param, struct refer_progress *progress)
1680{
1681 const pj_str_t str_replaces = { "Replaces", 8 };
1682 pj_str_t replaces_content;
1683 pjsip_replaces_hdr *replaces;
1684 int parsed_len;
1685 pjsip_dialog *dlg;
1686 SCOPE_ENTER(3, "%s", ast_channel_name(session->channel));
1687
1688 pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
1689
1690 /* Parsing the parameter as a Replaces header easily grabs the needed information */
1691 if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
1692 pj_strlen(&replaces_content), &parsed_len))) {
1693 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
1695 SCOPE_EXIT_RTN_VALUE(400, "%s: done: %d\n", ast_channel_name(session->channel), 400);
1696 }
1697
1698 /* See if the dialog is local, or remote */
1699 if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
1700 RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
1701 struct refer_attended *attended;
1702
1703 pjsip_dlg_dec_lock(dlg);
1704
1705 if (!other_session) {
1706 ast_debug(3, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it\n",
1708 SCOPE_EXIT_RTN_VALUE(503, "%s: done: %d\n", ast_channel_name(session->channel), 603);
1709 }
1710
1711 /* We defer actually doing the attended transfer to the other session so no deadlock can occur */
1712 if (!(attended = refer_attended_alloc(session, other_session, progress))) {
1713 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",
1715 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1716 }
1717
1719 ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not defer termination, rejecting\n",
1721 ao2_cleanup(attended);
1722 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1723 }
1724
1725 /* Push it to the other session, which will have both channels with minimal locking */
1726 if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {
1729 ao2_cleanup(attended);
1730 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1731 }
1732
1733 ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
1734 ast_channel_name(session->channel));
1735
1736 SCOPE_EXIT_RTN_VALUE(200, "%s: done: %d\n", ast_channel_name(session->channel), 200);
1737 } else {
1738 const char *context;
1739 struct refer_blind refer = { 0, };
1740 int response;
1741
1743
1744 if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
1745 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",
1747 SCOPE_EXIT_RTN_VALUE(404, "%s: done: %d\n", ast_channel_name(session->channel), 404);
1748 }
1749
1750 refer.context = context;
1751 refer.progress = progress;
1752 refer.rdata = rdata;
1753 refer.replaces = replaces;
1754 refer.refer_to = target_uri;
1755 refer.attended = 1;
1756
1758 ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting\n",
1759 ast_channel_name(session->channel),
1761 SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
1762 }
1763
1765 "external_replaces", context, refer_blind_callback, &refer));
1766
1768 if (response != 200) {
1770 }
1771
1772 SCOPE_EXIT_RTN_VALUE(response, "%s: done: %d\n", ast_channel_name(session->channel), response);
1773 }
1774}
1775
1776static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
1777 struct refer_progress *progress)
1778{
1779 const char *context;
1780 char exten[AST_MAX_EXTENSION];
1781 struct refer_blind refer = { 0, };
1782 int response;
1783
1784 /* If no explicit transfer context has been provided use their configured context */
1786
1787 /* Using the user portion of the target URI see if it exists as a valid extension in their context */
1788 ast_copy_pj_str(exten, &target->user, sizeof(exten));
1789
1790 /*
1791 * We may want to match in the dialplan without any user
1792 * options getting in the way.
1793 */
1795
1796 /* Uri without exten */
1797 if (ast_strlen_zero(exten)) {
1798 ast_copy_string(exten, "s", sizeof(exten));
1799 ast_debug(3, "Channel '%s' from endpoint '%s' attempted blind transfer to a target without extension. Target was set to 's@%s'\n",
1801 }
1802
1803 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
1804 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
1805 ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context);
1806 return 404;
1807 }
1808
1809 refer.context = context;
1810 refer.progress = progress;
1811 refer.rdata = rdata;
1812 refer.refer_to = target;
1813 refer.attended = 0;
1814
1816 ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer but could not defer termination, rejecting\n",
1817 ast_channel_name(session->channel),
1819 return 500;
1820 }
1821
1823 exten, context, refer_blind_callback, &refer));
1824
1826 if (response != 200) {
1828 }
1829
1830 return response;
1831}
1832
1833/*! \brief Structure used to retrieve channel from another session */
1835 /*! \brief Session we want the channel from */
1837 /*! \brief Channel from the session (with reference) */
1839 /*! \brief Bridge the channel is in */
1841};
1842
1843/*! \brief Task for invite replaces */
1844static int invite_replaces(void *data)
1845{
1846 struct invite_replaces *invite = data;
1847
1848 if (!invite->session->channel) {
1849 return -1;
1850 }
1851
1853 invite->channel = invite->session->channel;
1854
1856 return 0;
1857}
1858
1859static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1860{
1861 pjsip_dialog *other_dlg = NULL;
1862 pjsip_tx_data *packet;
1863 int response = 0;
1864 RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup);
1865 struct invite_replaces invite;
1866
1867 /* If a Replaces header is present make sure it is valid */
1868 if (pjsip_replaces_verify_request(rdata, &other_dlg, PJ_TRUE, &packet) != PJ_SUCCESS) {
1869 response = packet->msg->line.status.code;
1870 ast_assert(response != 0);
1871 pjsip_tx_data_dec_ref(packet);
1872 goto inv_replace_failed;
1873 }
1874
1875 /* If no other dialog exists then this INVITE request does not have a Replaces header */
1876 if (!other_dlg) {
1877 return 0;
1878 }
1879
1880 other_session = ast_sip_dialog_get_session(other_dlg);
1881 pjsip_dlg_dec_lock(other_dlg);
1882
1883 /* Don't accept an in-dialog INVITE with Replaces as it does not make much sense */
1884 if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
1885 response = 488;
1886 goto inv_replace_failed;
1887 }
1888
1889 if (!other_session) {
1890 ast_debug(3, "INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist\n",
1892 response = 481;
1893 goto inv_replace_failed;
1894 }
1895
1896 invite.session = other_session;
1897
1898 if (ast_sip_push_task_wait_serializer(other_session->serializer, invite_replaces,
1899 &invite)) {
1900 response = 481;
1901 goto inv_replace_failed;
1902 }
1903
1904 ast_channel_lock(session->channel);
1906 ast_channel_unlock(session->channel);
1907 ast_raw_answer(session->channel);
1908
1909 ast_debug(3, "INVITE with Replaces being attempted. '%s' --> '%s'\n",
1911
1912 /* Unhold the channel now, as later we are not having access to it anymore */
1913 ast_queue_unhold(session->channel);
1915
1916 if (!invite.bridge) {
1917 struct ast_channel *chan = session->channel;
1918
1919 /*
1920 * This will use a synchronous task but we aren't operating in
1921 * the serializer at this point in time, so it won't deadlock.
1922 */
1923 if (!ast_channel_move(invite.channel, chan)) {
1924 /*
1925 * We can't directly use session->channel because ast_channel_move()
1926 * does a masquerade which changes session->channel to a different
1927 * channel. To ensure we work on the right channel we store a
1928 * pointer locally before we begin so it remains valid.
1929 */
1930 ast_hangup(chan);
1931 } else {
1932 response = AST_CAUSE_FAILURE;
1933 }
1934 } else {
1935 if (ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL,
1937 response = AST_CAUSE_FAILURE;
1938 }
1939 }
1940
1941 ast_channel_unref(invite.channel);
1942 ao2_cleanup(invite.bridge);
1943
1944 if (!response) {
1945 /*
1946 * On success we cannot use session->channel in the debug message.
1947 * This thread either no longer has a ref to session->channel or
1948 * session->channel is no longer the original channel.
1949 */
1950 ast_debug(3, "INVITE with Replaces successfully completed.\n");
1951 } else {
1952 ast_debug(3, "INVITE with Replaces failed on channel '%s', hanging up with cause '%d'\n",
1953 ast_channel_name(session->channel), response);
1954 ast_channel_lock(session->channel);
1955 ast_channel_hangupcause_set(session->channel, response);
1956 ast_channel_unlock(session->channel);
1957 ast_hangup(session->channel);
1958 }
1959
1960 return 1;
1961
1962inv_replace_failed:
1963 if (session->inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
1964 ast_debug(3, "INVITE with Replaces failed on channel '%s', sending response of '%d'\n",
1965 ast_channel_name(session->channel), response);
1966 session->defer_terminate = 1;
1967 ast_hangup(session->channel);
1968
1969 if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS
1970 && packet) {
1972 }
1973 } else {
1974 ast_debug(3, "INVITE with Replaces in-dialog on channel '%s', hanging up\n",
1975 ast_channel_name(session->channel));
1976 ast_queue_hangup(session->channel);
1977 }
1978
1979 return 1;
1980}
1981
1982static int refer_incoming_refer_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1983{
1984 pjsip_generic_string_hdr *refer_to;
1985 char *uri;
1986 size_t uri_size;
1987 pjsip_uri *target;
1988 pjsip_sip_uri *target_uri;
1990 pjsip_param *replaces;
1991 int response;
1992
1993 static const pj_str_t str_refer_to = { "Refer-To", 8 };
1994 static const pj_str_t str_refer_to_s = { "r", 1 };
1995 static const pj_str_t str_replaces = { "Replaces", 8 };
1996
1997 SCOPE_ENTER(3, "%s\n", session->channel ? ast_channel_name(session->channel) : "unknown");
1998
1999 if (!session->channel) {
2000 /* No channel to refer. Likely because the call was just hung up. */
2001 pjsip_dlg_respond(session->inv_session->dlg, rdata, 404, NULL, NULL, NULL);
2002 ast_debug(3, "Received a REFER on a session with no channel from endpoint '%s'.\n",
2004 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2005 }
2006
2007 if (!session->endpoint->allowtransfer) {
2008 pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
2009 ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
2011 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2012 }
2013
2014 /* A Refer-To header is required */
2015 refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL);
2016 if (!refer_to) {
2017 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
2018 ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
2020 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2021 }
2022
2023 /* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri
2024 * as pjsip_parse_uri require a NULL terminated uri
2025 */
2026
2027 uri_size = pj_strlen(&refer_to->hvalue) + 1;
2028 uri = ast_alloca(uri_size);
2029 ast_copy_pj_str(uri, &refer_to->hvalue, uri_size);
2030
2031 target = pjsip_parse_uri(rdata->tp_info.pool, uri, uri_size - 1, 0);
2032
2033 if (!target
2034 || (!PJSIP_URI_SCHEME_IS_SIP(target)
2035 && !PJSIP_URI_SCHEME_IS_SIPS(target))) {
2036
2037 pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
2038 ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n",
2039 uri, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
2040 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2041 }
2042 target_uri = pjsip_uri_get_uri(target);
2043
2044 /* Set up REFER progress subscription if requested/possible */
2045 if (refer_progress_alloc(session, rdata, &progress)) {
2046 pjsip_dlg_respond(session->inv_session->dlg, rdata, 500, NULL, NULL, NULL);
2047 ast_debug(3, "Could not set up subscription for REFER on channel '%s' from endpoint '%s'\n",
2049 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2050 }
2051
2052 replaces = pjsip_param_find(&target_uri->header_param, &str_replaces);
2053 if (!replaces) {
2054 replaces = pjsip_param_find(&target_uri->other_param, &str_replaces);
2055 }
2056
2057 /* Determine if this is handled externally or an attended or blind transfer */
2058 if (session->transferhandling_ari) {
2059 ast_trace(-1, "%s: incoming ari\n", session->channel ? ast_channel_name(session->channel) : "unknown");
2060 response = refer_incoming_ari_request(session, rdata, target_uri, replaces, progress);
2061 } else if (replaces) {
2062 ast_trace(-1, "%s: incoming attended\n", session->channel ? ast_channel_name(session->channel) : "unknown");
2063 response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
2064 } else {
2065 ast_trace(-1, "%s: incoming blind\n", session->channel ? ast_channel_name(session->channel) : "unknown");
2066 response = refer_incoming_blind_request(session, rdata, target_uri, progress);
2067 }
2068
2069 if (progress->no_refer_sub) {
2070 /* The transferer has requested no subscription, so send a final response immediately */
2071 pjsip_tx_data *tdata;
2072 const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
2073 const pj_str_t str_false = { "false", 5 };
2074 pjsip_hdr *hdr;
2075
2076 ast_trace(-1, "%s: No refer sub from endpoint '%s'. Sending reponse %d\n", ast_channel_name(session->channel),
2077 ast_sorcery_object_get_id(session->endpoint), response);
2078
2079 if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, response, NULL, &tdata) != PJ_SUCCESS) {
2080 pjsip_dlg_respond(session->inv_session->dlg, rdata, response, NULL, NULL, NULL);
2081 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2082 }
2083
2084 hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
2085 pjsip_msg_add_hdr(tdata->msg, hdr);
2086
2087 pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2088
2089 } else if (response != 200) {
2090 /* Since this failed we can send a final NOTIFY now and terminate the subscription */
2091 struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
2092
2093 if (notification) {
2094 /* The refer_progress_notify function will call ao2_cleanup on this for us */
2095 if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
2096 ao2_cleanup(notification);
2097 }
2098 }
2099 }
2100
2101 SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
2102}
2103
2104static int refer_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
2105{
2106 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
2108 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_invite_method)) {
2110 } else {
2111 return 0;
2112 }
2113}
2114
2115/*!
2116 * \brief Use the value of a channel variable as the value of a SIP header
2117 *
2118 * This looks up a variable name on a channel, then takes that value and adds
2119 * it to an outgoing SIP request. If the header already exists on the message,
2120 * then no action is taken.
2121 *
2122 * \pre chan is locked.
2123 *
2124 * \param chan The channel on which to find the variable.
2125 * \param var_name The name of the channel variable to use.
2126 * \param header_name The name of the SIP header to add to the outgoing message.
2127 * \param tdata The outgoing SIP message on which to add the header
2128 */
2129static void add_header_from_channel_var(struct ast_channel *chan, const char *var_name, const char *header_name, pjsip_tx_data *tdata)
2130{
2131 const char *var_value;
2132 pj_str_t pj_header_name;
2133 pjsip_hdr *header;
2134
2135 var_value = pbx_builtin_getvar_helper(chan, var_name);
2136 if (ast_strlen_zero(var_value)) {
2137 return;
2138 }
2139
2140 pj_cstr(&pj_header_name, header_name);
2141 header = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_header_name, NULL);
2142 if (header) {
2143 return;
2144 }
2145 ast_sip_add_header(tdata, header_name, var_value);
2146}
2147
2148static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
2149{
2150 if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method)
2151 || !session->channel
2152 || session->inv_session->state != PJSIP_INV_STATE_NULL) {
2153 return;
2154 }
2155
2156 ast_channel_lock(session->channel);
2157 add_header_from_channel_var(session->channel, "SIPREPLACESHDR", "Replaces", tdata);
2158 add_header_from_channel_var(session->channel, "SIPREFERREDBYHDR", "Referred-By", tdata);
2159 ast_channel_unlock(session->channel);
2160}
2161
2164 .incoming_request = refer_incoming_request,
2165 .outgoing_request = refer_outgoing_request,
2166};
2167
2168static int load_module(void)
2169{
2170 const pj_str_t str_norefersub = { "norefersub", 10 };
2171
2172 pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint());
2173 pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint());
2174
2175 if (ast_sip_get_norefersub()) {
2176 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub);
2177 }
2178
2181 }
2182
2184 if (!refer_serializer) {
2187 }
2188
2192
2194
2196}
2197
2207
2208AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Blind and Attended Transfer Support",
2209 .support_level = AST_MODULE_SUPPORT_CORE,
2210 .load = load_module,
2211 .unload = unload_module,
2212 .load_pri = AST_MODPRI_APP_DEPEND,
2213 .requires = "res_pjsip,res_pjsip_session,res_pjsip_pubsub",
jack_status_t status
Definition app_jack.c:149
const char * str
Definition app_jack.c:150
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition astmm.c:1739
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
Bridging API.
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
Definition bridge.c: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)
#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:2092
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:2285
#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:3224
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:3561
int ast_sip_update_from(pjsip_tx_data *tdata, char *from)
Overwrite fields in the outbound 'From' header.
Definition res_pjsip.c:3358
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition res_pjsip.h:3396
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:2176
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:1977
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:3298
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:2006
#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