Asterisk - The Open Source Telephony Project  GIT-master-060ce10
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"
36 #include "asterisk/taskprocessor.h"
37 #include "asterisk/bridge.h"
38 #include "asterisk/framehook.h"
41 #include "asterisk/causes.h"
42 
43 /*! \brief REFER Progress structure */
45  /*! \brief Subscription to provide updates on */
46  pjsip_evsub *sub;
47  /*! \brief Dialog for subscription */
48  pjsip_dialog *dlg;
49  /*! \brief Received packet, used to construct final response in case no subscription exists */
50  pjsip_rx_data *rdata;
51  /*! \brief Frame hook for monitoring REFER progress */
52  int framehook;
53  /*! \brief Last received subclass in frame hook */
54  int subclass;
55  /*! \brief Serializer for notifications */
57  /*! \brief Stasis subscription for bridge events */
59  /*! \brief Reference to transfer_channel_data related to the refer */
61  /*! \brief Uniqueid of transferee channel */
62  char *transferee;
63  /*! \brief Non-zero if the 100 notify has been sent */
64  int sent_100;
65  /*! \brief Whether to notifies all the progress details on blind transfer */
66  unsigned int refer_blind_progress;
67 };
68 
69 /*! \brief REFER Progress notification structure */
71  /*! \brief Refer progress structure to send notification on */
73  /*! \brief SIP response code to send */
74  int response;
75  /*! \brief Subscription state */
76  pjsip_evsub_state state;
77 };
78 
79 /*! \brief REFER Progress module, used to attach REFER progress structure to subscriptions */
80 static pjsip_module refer_progress_module = {
81  .name = { "REFER Progress", 14 },
82  .id = -1,
83 };
84 
85 /*! \brief Destructor for REFER Progress notification structure */
87 {
88  struct refer_progress_notification *notification = obj;
89 
90  ao2_cleanup(notification->progress);
91 }
92 
93 /*! \brief Allocator for REFER Progress notification structure */
95  pjsip_evsub_state state)
96 {
97  struct refer_progress_notification *notification = ao2_alloc(sizeof(*notification), refer_progress_notification_destroy);
98 
99  if (!notification) {
100  return NULL;
101  }
102 
103  ao2_ref(progress, +1);
104  notification->progress = progress;
105  notification->response = response;
106  notification->state = state;
107 
108  return notification;
109 }
110 
111 /*! \brief Serialized callback for subscription notification */
112 static int refer_progress_notify(void *data)
113 {
114  RAII_VAR(struct refer_progress_notification *, notification, data, ao2_cleanup);
115  pjsip_evsub *sub;
116  pjsip_tx_data *tdata;
117 
118  /* If the subscription has already been terminated we can't send a notification */
119  if (!(sub = notification->progress->sub)) {
120  ast_debug(3, "Not sending NOTIFY of response '%d' and state '%u' on progress monitor '%p' as subscription has been terminated\n",
121  notification->response, notification->state, notification->progress);
122  return 0;
123  }
124 
125  /* If the subscription is being terminated we want to actually remove the progress structure here to
126  * stop a deadlock from occurring - basically terminated changes the state which queues a synchronous task
127  * but we are already running a task... thus it would deadlock */
128  if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
129  ast_debug(3, "Subscription '%p' is being terminated as a result of a NOTIFY, removing REFER progress structure early on progress monitor '%p'\n",
130  notification->progress->sub, notification->progress);
131  pjsip_dlg_inc_lock(notification->progress->dlg);
132  pjsip_evsub_set_mod_data(notification->progress->sub, refer_progress_module.id, NULL);
133  pjsip_dlg_dec_lock(notification->progress->dlg);
134 
135  /* This is for dropping the reference on the subscription */
136  ao2_cleanup(notification->progress);
137 
138  notification->progress->sub = NULL;
139  }
140 
141  /* Send a deferred initial 100 Trying SIP frag NOTIFY if we haven't already. */
142  if (!notification->progress->sent_100) {
143  notification->progress->sent_100 = 1;
144  if (notification->response != 100) {
145  ast_debug(3, "Sending initial 100 Trying NOTIFY for progress monitor '%p'\n",
146  notification->progress);
147  if (pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) {
148  pjsip_xfer_send_request(sub, tdata);
149  }
150  }
151  }
152 
153  ast_debug(3, "Sending NOTIFY with response '%d' and state '%u' on subscription '%p' and progress monitor '%p'\n",
154  notification->response, notification->state, sub, notification->progress);
155 
156  /* Actually send the notification */
157  if (pjsip_xfer_notify(sub, notification->state, notification->response, NULL, &tdata) == PJ_SUCCESS) {
158  pjsip_xfer_send_request(sub, tdata);
159  }
160 
161  return 0;
162 }
163 
164 static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
165  struct stasis_message *message)
166 {
167  struct refer_progress *progress = data;
168  struct ast_bridge_blob *enter_blob;
169  struct refer_progress_notification *notification;
170  struct ast_channel *chan;
171 
172  if (stasis_subscription_final_message(sub, message)) {
173  ao2_ref(progress, -1);
174  return;
175  }
176 
178  /* Don't care */
179  return;
180  }
181 
182  enter_blob = stasis_message_data(message);
183  if (strcmp(enter_blob->channel->base->uniqueid, progress->transferee)) {
184  /* Don't care */
185  return;
186  }
187 
188  if (!progress->transfer_data->completed) {
189  /* We can't act on this message because the transfer_channel_data doesn't show that
190  * the transfer is ready to progress */
191  return;
192  }
193 
194  /* OMG the transferee is joining a bridge. His call got answered! */
195  notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
196  if (notification) {
197  if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
198  ao2_cleanup(notification);
199  }
200  progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
201  }
202 
203  chan = ast_channel_get_by_name(progress->transferee);
204  if (!chan) {
205  /* The channel is already gone */
206  return;
207  }
208 
209  ast_channel_lock(chan);
210  ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as it has joined a bridge\n",
211  ast_channel_name(chan));
212  ast_framehook_detach(chan, progress->framehook);
213  ast_channel_unlock(chan);
214 
215  ast_channel_unref(chan);
216 }
217 
218 /*! \brief Progress monitoring frame hook - examines frames to determine state of transfer */
219 static struct ast_frame *refer_progress_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
220 {
221  struct refer_progress *progress = data;
222  struct refer_progress_notification *notification = NULL;
223 
224  /* We only care about frames *to* the channel */
225  if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
226  return f;
227  }
228 
229  /* If the completed flag hasn't been raised, skip this pass. */
230  if (!progress->transfer_data->completed) {
231  return f;
232  }
233 
234  /* Determine the state of the REFER based on the control frames (or voice frames) passing */
235  if (f->frametype == AST_FRAME_VOICE && !progress->subclass) {
236  /* Media is passing without progress, this means the call has been answered */
237  progress->subclass = AST_CONTROL_ANSWER;
238  notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
239  } else if (f->frametype == AST_FRAME_CONTROL) {
240  /* Based on the control frame being written we can send a NOTIFY advising of the progress */
242  /* Don't set progress->subclass; an ANSWER can still follow */
243  notification = refer_progress_notification_alloc(progress, 180, PJSIP_EVSUB_STATE_ACTIVE);
244  } else if (f->subclass.integer == AST_CONTROL_BUSY) {
245  progress->subclass = f->subclass.integer;
246  notification = refer_progress_notification_alloc(progress, 486, PJSIP_EVSUB_STATE_TERMINATED);
247  } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
248  progress->subclass = f->subclass.integer;
249  notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
250  } else if (f->subclass.integer == AST_CONTROL_PROGRESS) {
251  /* Don't set progress->subclass; an ANSWER can still follow */
252  notification = refer_progress_notification_alloc(progress, 183, PJSIP_EVSUB_STATE_ACTIVE);
253  } else if (f->subclass.integer == AST_CONTROL_PROCEEDING) {
254  /* Don't set progress->subclass; an ANSWER can still follow */
255  notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
256  } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
257  progress->subclass = f->subclass.integer;
258  notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
259  }
260  }
261 
262  /* If a notification is due to be sent push it to the thread pool */
263  if (notification) {
264  /* If the subscription is being terminated we don't need the frame hook any longer */
265  if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
266  ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
267  ast_channel_name(chan));
268  ast_framehook_detach(chan, progress->framehook);
269  }
270 
271  if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
272  ao2_cleanup(notification);
273  }
274  }
275 
276  return f;
277 }
278 
279 /*! \brief Destroy callback for monitoring framehook */
280 static void refer_progress_framehook_destroy(void *data)
281 {
282  struct refer_progress *progress = data;
283  struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
284 
285  if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
286  ao2_cleanup(notification);
287  }
288 
289  if (progress->bridge_sub) {
290  progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
291  }
292 
293  ao2_cleanup(progress);
294 }
295 
296 /*! \brief Serialized callback for subscription termination */
297 static int refer_progress_terminate(void *data)
298 {
299  struct refer_progress *progress = data;
300 
301  /* The subscription is no longer valid */
302  progress->sub = NULL;
303 
304  return 0;
305 }
306 
307 /*! \brief Callback for REFER subscription state changes */
308 static void refer_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
309 {
310  struct refer_progress *progress = pjsip_evsub_get_mod_data(sub, refer_progress_module.id);
311 
312  /* If being destroyed queue it up to the serializer */
313  if (progress && (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)) {
314  /* To prevent a deadlock race condition we unlock the dialog so other serialized tasks can execute */
315  ast_debug(3, "Subscription '%p' has been remotely terminated, waiting for other tasks to complete on progress monitor '%p'\n",
316  sub, progress);
317 
318  /* It's possible that a task is waiting to remove us already, so bump the refcount of progress so it doesn't get destroyed */
319  ao2_ref(progress, +1);
320  pjsip_dlg_dec_lock(progress->dlg);
321  /*
322  * XXX We are always going to execute this inline rather than
323  * in the serializer because this function is a PJPROJECT
324  * callback and thus has to be a SIP servant thread.
325  *
326  * The likely remedy is to push most of this function into
327  * refer_progress_terminate() with ast_sip_push_task().
328  */
330  pjsip_dlg_inc_lock(progress->dlg);
331  ao2_ref(progress, -1);
332 
333  ast_debug(3, "Subscription '%p' removed from progress monitor '%p'\n", sub, progress);
334 
335  /* Since it was unlocked it is possible for this to have been removed already, so check again */
336  if (pjsip_evsub_get_mod_data(sub, refer_progress_module.id)) {
337  pjsip_evsub_set_mod_data(sub, refer_progress_module.id, NULL);
338  ao2_cleanup(progress);
339  }
340  }
341 }
342 
343 /*! \brief Callback structure for subscription */
344 static pjsip_evsub_user refer_progress_evsub_cb = {
345  .on_evsub_state = refer_progress_on_evsub_state,
346 };
347 
348 /*! \brief Destructor for REFER progress sutrcture */
349 static void refer_progress_destroy(void *obj)
350 {
351  struct refer_progress *progress = obj;
352 
353  if (progress->bridge_sub) {
354  progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
355  }
356 
357  ao2_cleanup(progress->transfer_data);
358 
359  ast_free(progress->transferee);
361 }
362 
363 /*! \brief Internal helper function which sets up a refer progress structure if needed */
364 static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata, struct refer_progress **progress)
365 {
366  const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
367  pjsip_generic_string_hdr *refer_sub = NULL;
368  const pj_str_t str_true = { "true", 4 };
369  pjsip_hdr hdr_list;
370  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
371 
372  *progress = NULL;
373 
374  /* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */
375  refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
376  if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4))) {
377  return 0;
378  }
379 
380  if (!(*progress = ao2_alloc(sizeof(struct refer_progress), refer_progress_destroy))) {
381  return -1;
382  }
383 
384  ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
385  progress, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
386 
387  (*progress)->refer_blind_progress = session->endpoint->refer_blind_progress;
388 
389  (*progress)->framehook = -1;
390 
391  /* To prevent a potential deadlock we need the dialog so we can lock/unlock */
392  (*progress)->dlg = session->inv_session->dlg;
393 
394  /* Create name with seq number appended. */
395  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/refer/%s",
397 
398  if (!((*progress)->serializer = ast_sip_create_serializer(tps_name))) {
399  goto error;
400  }
401 
402  /* Create the implicit subscription for monitoring of this transfer */
403  if (pjsip_xfer_create_uas(session->inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
404  goto error;
405  }
406 
407  /* Associate the REFER progress structure with the subscription */
408  ao2_ref(*progress, +1);
409  pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
410 
411  pj_list_init(&hdr_list);
412  if (refer_sub) {
413  pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->inv_session->dlg->pool, &str_refer_sub, &str_true);
414 
415  pj_list_push_back(&hdr_list, hdr);
416  }
417 
418  /* Accept the REFER request */
419  ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress);
420  pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
421 
422  return 0;
423 
424 error:
425  ao2_cleanup(*progress);
426  *progress = NULL;
427  return -1;
428 }
429 
430 /*! \brief Structure for attended transfer task */
432  /*! \brief Transferer session */
434  /*! \brief Transferer channel */
436  /*! \brief Second transferer session */
438  /*! \brief Optional refer progress structure */
440 };
441 
442 /*! \brief Destructor for attended transfer task */
443 static void refer_attended_destroy(void *obj)
444 {
445  struct refer_attended *attended = obj;
446 
447  ao2_cleanup(attended->transferer);
449  ao2_cleanup(attended->transferer_second);
450  ao2_cleanup(attended->progress);
451 }
452 
453 /*! \brief Allocator for attended transfer task */
456  struct refer_progress *progress)
457 {
458  struct refer_attended *attended;
459 
460  attended = ao2_alloc_options(sizeof(*attended), refer_attended_destroy,
462  if (!attended) {
463  return NULL;
464  }
465 
466  ao2_ref(transferer, +1);
467  attended->transferer = transferer;
468  ast_channel_ref(transferer->channel);
469  attended->transferer_chan = transferer->channel;
470  ao2_ref(transferer_second, +1);
472 
473  if (progress) {
474  ao2_ref(progress, +1);
475  attended->progress = progress;
476  }
477 
478  return attended;
479 }
480 
481 static int session_end_if_deferred_task(void *data)
482 {
483  struct ast_sip_session *session = data;
484 
486  ao2_ref(session, -1);
487  return 0;
488 }
489 
490 static int defer_termination_cancel_task(void *data)
491 {
492  struct ast_sip_session *session = data;
493 
496  ao2_ref(session, -1);
497  return 0;
498 }
499 
500 /*!
501  * \internal
502  * \brief Convert transfer enum to SIP response code.
503  * \since 13.3.0
504  *
505  * \param xfer_code Core transfer function enum result.
506  *
507  * \return SIP response code
508  */
509 static int xfer_response_code2sip(enum ast_transfer_result xfer_code)
510 {
511  int response;
512 
513  response = 503;
514  switch (xfer_code) {
516  response = 400;
517  break;
519  response = 403;
520  break;
522  response = 500;
523  break;
525  response = 200;
526  break;
527  }
528  return response;
529 }
530 
531 /*! \brief Task for attended transfer executed by attended->transferer_second serializer */
532 static int refer_attended_task(void *data)
533 {
534  struct refer_attended *attended = data;
535  int response;
536  int (*task_cb)(void *data);
537 
538  if (attended->transferer_second->channel) {
539  ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
542 
544  attended->transferer_chan,
545  attended->transferer_second->channel));
546 
547  ast_debug(3, "Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
550  response);
551  } else {
552  ast_debug(3, "Received REFER request on channel '%s' but other channel has gone.\n",
553  ast_channel_name(attended->transferer_chan));
554  response = 603;
555  }
556 
557  if (attended->progress) {
558  struct refer_progress_notification *notification;
559 
560  notification = refer_progress_notification_alloc(attended->progress, response,
561  PJSIP_EVSUB_STATE_TERMINATED);
562  if (notification) {
563  refer_progress_notify(notification);
564  }
565  }
566 
567  if (response == 200) {
569  } else {
571  }
572  if (!ast_sip_push_task(attended->transferer->serializer,
573  task_cb, attended->transferer)) {
574  /* Gave the ref to the pushed task. */
575  attended->transferer = NULL;
576  } else {
577  /* Do this anyway even though it is the wrong serializer. */
579  }
580 
581  ao2_ref(attended, -1);
582  return 0;
583 }
584 
585 /*! \brief Structure for blind transfer callback details */
586 struct refer_blind {
587  /*! \brief Context being used for transfer */
588  const char *context;
589  /*! \brief Optional progress structure */
591  /*! \brief REFER message */
592  pjsip_rx_data *rdata;
593  /*! \brief Optional Replaces header */
594  pjsip_replaces_hdr *replaces;
595  /*! \brief Optional Refer-To header */
596  pjsip_sip_uri *refer_to;
597  /*! \brief Attended transfer flag */
598  unsigned int attended:1;
599 };
600 
601 /*! \brief Blind transfer callback function */
602 static void refer_blind_callback(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
603  enum ast_transfer_type transfer_type)
604 {
605  struct refer_blind *refer = user_data_wrapper->data;
606  pjsip_generic_string_hdr *referred_by;
607 
608  static const pj_str_t str_referred_by = { "Referred-By", 11 };
609  static const pj_str_t str_referred_by_s = { "b", 1 };
610 
611  pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
612 
613  if (refer->progress && !refer->attended && !refer->progress->refer_blind_progress) {
614  /* If blind transfer and endpoint doesn't want to receive all the progress details */
616  PJSIP_EVSUB_STATE_TERMINATED);
617 
618  if (notification) {
619  refer_progress_notify(notification);
620  }
621  } else if (refer->progress) {
622  /* If attended transfer and progress monitoring is being done attach a frame hook so we can monitor it */
623  struct ast_framehook_interface hook = {
625  .event_cb = refer_progress_framehook,
626  .destroy_cb = refer_progress_framehook_destroy,
627  .data = refer->progress,
628  .disable_inheritance = 1,
629  };
630 
632  if (!refer->progress->transferee) {
634  PJSIP_EVSUB_STATE_TERMINATED);
635 
636  ast_log(LOG_WARNING, "Could not copy channel name '%s' during transfer - assuming success\n",
637  ast_channel_name(chan));
638 
639  if (notification) {
640  refer_progress_notify(notification);
641  }
642  }
643 
644  /* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
645  ao2_ref(user_data_wrapper, +1);
646  refer->progress->transfer_data = user_data_wrapper;
647 
648  /* We need to bump the reference count up on the progress structure since it is in the frame hook now */
649  ao2_ref(refer->progress, +1);
650 
651  /* If we can't attach a frame hook for whatever reason send a notification of success immediately */
652  ast_channel_lock(chan);
653  refer->progress->framehook = ast_framehook_attach(chan, &hook);
654  ast_channel_unlock(chan);
655  if (refer->progress->framehook < 0) {
657  PJSIP_EVSUB_STATE_TERMINATED);
658 
659  ast_log(LOG_WARNING, "Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
660  ast_channel_name(chan));
661 
662  if (notification) {
663  refer_progress_notify(notification);
664  }
665 
666  ao2_cleanup(refer->progress);
667  }
668 
669  /* We need to bump the reference count for the stasis subscription */
670  ao2_ref(refer->progress, +1);
671  /* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
672  * detect if the transfer target has answered the call
673  */
675  if (!refer->progress->bridge_sub) {
677  PJSIP_EVSUB_STATE_TERMINATED);
678 
679  ast_log(LOG_WARNING, "Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success\n",
680  ast_channel_name(chan));
681 
682  if (notification) {
683  refer_progress_notify(notification);
684  }
685 
686  ast_channel_lock(chan);
687  ast_framehook_detach(chan, refer->progress->framehook);
688  ast_channel_unlock(chan);
689 
690  ao2_cleanup(refer->progress);
691  } else {
695  }
696  }
697 
698  pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL));
699 
700  referred_by = pjsip_msg_find_hdr_by_names(refer->rdata->msg_info.msg,
701  &str_referred_by, &str_referred_by_s, NULL);
702  if (referred_by) {
703  size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
704  char *uri = ast_alloca(uri_size);
705 
706  ast_copy_pj_str(uri, &referred_by->hvalue, uri_size);
707  pbx_builtin_setvar_helper(chan, "__SIPREFERREDBYHDR", S_OR(uri, NULL));
708  } else {
709  pbx_builtin_setvar_helper(chan, "SIPREFERREDBYHDR", NULL);
710  }
711 
712  if (refer->replaces) {
713  char replaces[512];
714  char *replaces_val = NULL;
715  int len;
716 
717  len = pjsip_hdr_print_on(refer->replaces, replaces, sizeof(replaces) - 1);
718  if (len != -1) {
719  /* pjsip_hdr_print_on does not NULL terminate the buffer */
720  replaces[len] = '\0';
721  replaces_val = replaces + sizeof("Replaces:");
722  }
723  pbx_builtin_setvar_helper(chan, "__SIPREPLACESHDR", replaces_val);
724  } else {
725  pbx_builtin_setvar_helper(chan, "SIPREPLACESHDR", NULL);
726  }
727 
728  if (refer->refer_to) {
729  char refer_to[PJSIP_MAX_URL_SIZE];
730 
731  pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->refer_to, refer_to, sizeof(refer_to));
732  pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", S_OR(refer_to, NULL));
733  } else {
734  pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", NULL);
735  }
736 }
737 
738 /*!
739  * \internal
740  * \brief Set the passed in context variable to the determined transfer context.
741  * \since 13.3.0
742  *
743  * \param context Set to the determined transfer context.
744  * \param session INVITE dialog SIP session.
745  */
746 #define DETERMINE_TRANSFER_CONTEXT(context, session) \
747  do { \
748  ast_channel_lock((session)->channel); \
749  context = pbx_builtin_getvar_helper((session)->channel, "TRANSFER_CONTEXT"); \
750  if (ast_strlen_zero(context)) { \
751  context = (session)->endpoint->context; \
752  } else { \
753  context = ast_strdupa(context); \
754  } \
755  ast_channel_unlock((session)->channel); \
756  } while (0) \
757 
758 static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri,
759  pjsip_param *replaces_param, struct refer_progress *progress)
760 {
761  const pj_str_t str_replaces = { "Replaces", 8 };
762  pj_str_t replaces_content;
763  pjsip_replaces_hdr *replaces;
764  int parsed_len;
765  pjsip_dialog *dlg;
766 
767  pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
768 
769  /* Parsing the parameter as a Replaces header easily grabs the needed information */
770  if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
771  pj_strlen(&replaces_content), &parsed_len))) {
772  ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
774  return 400;
775  }
776 
777  /* See if the dialog is local, or remote */
778  if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
779  RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
780  struct refer_attended *attended;
781 
782  pjsip_dlg_dec_lock(dlg);
783 
784  if (!other_session) {
785  ast_debug(3, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it\n",
787  return 603;
788  }
789 
790  /* We defer actually doing the attended transfer to the other session so no deadlock can occur */
791  if (!(attended = refer_attended_alloc(session, other_session, progress))) {
792  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",
794  return 500;
795  }
796 
797  if (ast_sip_session_defer_termination(session)) {
798  ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not defer termination, rejecting\n",
800  ao2_cleanup(attended);
801  return 500;
802  }
803 
804  /* Push it to the other session, which will have both channels with minimal locking */
805  if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {
808  ao2_cleanup(attended);
809  return 500;
810  }
811 
812  ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
813  ast_channel_name(session->channel));
814 
815  return 200;
816  } else {
817  const char *context;
818  struct refer_blind refer = { 0, };
819  int response;
820 
821  DETERMINE_TRANSFER_CONTEXT(context, session);
822 
823  if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
824  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",
825  ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), context);
826  return 404;
827  }
828 
829  refer.context = context;
830  refer.progress = progress;
831  refer.rdata = rdata;
832  refer.replaces = replaces;
833  refer.refer_to = target_uri;
834  refer.attended = 1;
835 
836  if (ast_sip_session_defer_termination(session)) {
837  ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting\n",
838  ast_channel_name(session->channel),
840  return 500;
841  }
842 
844  "external_replaces", context, refer_blind_callback, &refer));
845 
847  if (response != 200) {
849  }
850 
851  return response;
852  }
853 }
854 
855 static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
856  struct refer_progress *progress)
857 {
858  const char *context;
859  char exten[AST_MAX_EXTENSION];
860  struct refer_blind refer = { 0, };
861  int response;
862 
863  /* If no explicit transfer context has been provided use their configured context */
864  DETERMINE_TRANSFER_CONTEXT(context, session);
865 
866  /* Using the user portion of the target URI see if it exists as a valid extension in their context */
867  ast_copy_pj_str(exten, &target->user, sizeof(exten));
868 
869  /*
870  * We may want to match in the dialplan without any user
871  * options getting in the way.
872  */
874 
875  /* Uri without exten */
876  if (ast_strlen_zero(exten)) {
877  ast_copy_string(exten, "s", sizeof(exten));
878  ast_debug(3, "Channel '%s' from endpoint '%s' attempted blind transfer to a target without extension. Target was set to 's@%s'\n",
879  ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), context);
880  }
881 
882  if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
883  ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
884  ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context);
885  return 404;
886  }
887 
888  refer.context = context;
889  refer.progress = progress;
890  refer.rdata = rdata;
891  refer.refer_to = target;
892  refer.attended = 0;
893 
894  if (ast_sip_session_defer_termination(session)) {
895  ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer but could not defer termination, rejecting\n",
896  ast_channel_name(session->channel),
898  return 500;
899  }
900 
902  exten, context, refer_blind_callback, &refer));
903 
905  if (response != 200) {
907  }
908 
909  return response;
910 }
911 
912 /*! \brief Structure used to retrieve channel from another session */
914  /*! \brief Session we want the channel from */
916  /*! \brief Channel from the session (with reference) */
918  /*! \brief Bridge the channel is in */
920 };
921 
922 /*! \brief Task for invite replaces */
923 static int invite_replaces(void *data)
924 {
925  struct invite_replaces *invite = data;
926 
927  if (!invite->session->channel) {
928  return -1;
929  }
930 
931  ast_channel_ref(invite->session->channel);
932  invite->channel = invite->session->channel;
933 
935  return 0;
936 }
937 
938 static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
939 {
940  pjsip_dialog *other_dlg = NULL;
941  pjsip_tx_data *packet;
942  int response = 0;
943  RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup);
944  struct invite_replaces invite;
945 
946  /* If a Replaces header is present make sure it is valid */
947  if (pjsip_replaces_verify_request(rdata, &other_dlg, PJ_TRUE, &packet) != PJ_SUCCESS) {
948  response = packet->msg->line.status.code;
949  ast_assert(response != 0);
950  pjsip_tx_data_dec_ref(packet);
951  goto inv_replace_failed;
952  }
953 
954  /* If no other dialog exists then this INVITE request does not have a Replaces header */
955  if (!other_dlg) {
956  return 0;
957  }
958 
959  other_session = ast_sip_dialog_get_session(other_dlg);
960  pjsip_dlg_dec_lock(other_dlg);
961 
962  /* Don't accept an in-dialog INVITE with Replaces as it does not make much sense */
963  if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
964  response = 488;
965  goto inv_replace_failed;
966  }
967 
968  if (!other_session) {
969  ast_debug(3, "INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist\n",
971  response = 481;
972  goto inv_replace_failed;
973  }
974 
975  invite.session = other_session;
976 
977  if (ast_sip_push_task_wait_serializer(other_session->serializer, invite_replaces,
978  &invite)) {
979  response = 481;
980  goto inv_replace_failed;
981  }
982 
983  ast_channel_lock(session->channel);
985  ast_channel_unlock(session->channel);
986  ast_raw_answer(session->channel);
987 
988  ast_debug(3, "INVITE with Replaces being attempted. '%s' --> '%s'\n",
989  ast_channel_name(session->channel), ast_channel_name(invite.channel));
990 
991  if (!invite.bridge) {
992  struct ast_channel *chan = session->channel;
993 
994  /*
995  * This will use a synchronous task but we aren't operating in
996  * the serializer at this point in time, so it won't deadlock.
997  */
998  if (!ast_channel_move(invite.channel, chan)) {
999  /*
1000  * We can't directly use session->channel because ast_channel_move()
1001  * does a masquerade which changes session->channel to a different
1002  * channel. To ensure we work on the right channel we store a
1003  * pointer locally before we begin so it remains valid.
1004  */
1005  ast_hangup(chan);
1006  } else {
1007  response = AST_CAUSE_FAILURE;
1008  }
1009  } else {
1010  if (ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL,
1012  response = AST_CAUSE_FAILURE;
1013  }
1014  }
1015 
1016  ast_channel_unref(invite.channel);
1017  ao2_cleanup(invite.bridge);
1018 
1019  if (!response) {
1020  /*
1021  * On success we cannot use session->channel in the debug message.
1022  * This thread either no longer has a ref to session->channel or
1023  * session->channel is no longer the original channel.
1024  */
1025  ast_debug(3, "INVITE with Replaces successfully completed.\n");
1026  } else {
1027  ast_debug(3, "INVITE with Replaces failed on channel '%s', hanging up with cause '%d'\n",
1028  ast_channel_name(session->channel), response);
1029  ast_channel_lock(session->channel);
1030  ast_channel_hangupcause_set(session->channel, response);
1031  ast_channel_unlock(session->channel);
1032  ast_hangup(session->channel);
1033  }
1034 
1035  return 1;
1036 
1037 inv_replace_failed:
1038  if (session->inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
1039  ast_debug(3, "INVITE with Replaces failed on channel '%s', sending response of '%d'\n",
1040  ast_channel_name(session->channel), response);
1041  session->defer_terminate = 1;
1042  ast_hangup(session->channel);
1043 
1044  if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS
1045  && packet) {
1046  ast_sip_session_send_response(session, packet);
1047  }
1048  } else {
1049  ast_debug(3, "INVITE with Replaces in-dialog on channel '%s', hanging up\n",
1050  ast_channel_name(session->channel));
1051  ast_queue_hangup(session->channel);
1052  }
1053 
1054  return 1;
1055 }
1056 
1057 static int refer_incoming_refer_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1058 {
1059  pjsip_generic_string_hdr *refer_to;
1060  char *uri;
1061  size_t uri_size;
1062  pjsip_uri *target;
1063  pjsip_sip_uri *target_uri;
1065  pjsip_param *replaces;
1066  int response;
1067 
1068  static const pj_str_t str_refer_to = { "Refer-To", 8 };
1069  static const pj_str_t str_refer_to_s = { "r", 1 };
1070  static const pj_str_t str_replaces = { "Replaces", 8 };
1071 
1072  if (!session->channel) {
1073  /* No channel to refer. Likely because the call was just hung up. */
1074  pjsip_dlg_respond(session->inv_session->dlg, rdata, 404, NULL, NULL, NULL);
1075  ast_debug(3, "Received a REFER on a session with no channel from endpoint '%s'.\n",
1077  return 0;
1078  }
1079 
1080  if (!session->endpoint->allowtransfer) {
1081  pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
1082  ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
1084  return 0;
1085  }
1086 
1087  /* A Refer-To header is required */
1088  refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL);
1089  if (!refer_to) {
1090  pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1091  ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
1093  return 0;
1094  }
1095 
1096  /* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri
1097  * as pjsip_parse_uri require a NULL terminated uri
1098  */
1099 
1100  uri_size = pj_strlen(&refer_to->hvalue) + 1;
1101  uri = ast_alloca(uri_size);
1102  ast_copy_pj_str(uri, &refer_to->hvalue, uri_size);
1103 
1104  target = pjsip_parse_uri(rdata->tp_info.pool, uri, uri_size - 1, 0);
1105 
1106  if (!target
1107  || (!PJSIP_URI_SCHEME_IS_SIP(target)
1108  && !PJSIP_URI_SCHEME_IS_SIPS(target))) {
1109 
1110  pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
1111  ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n",
1112  uri, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
1113  return 0;
1114  }
1115  target_uri = pjsip_uri_get_uri(target);
1116 
1117  /* Set up REFER progress subscription if requested/possible */
1118  if (refer_progress_alloc(session, rdata, &progress)) {
1119  pjsip_dlg_respond(session->inv_session->dlg, rdata, 500, NULL, NULL, NULL);
1120  ast_debug(3, "Could not set up subscription for REFER on channel '%s' from endpoint '%s'\n",
1122  return 0;
1123  }
1124 
1125  /* Determine if this is an attended or blind transfer */
1126  if ((replaces = pjsip_param_find(&target_uri->header_param, &str_replaces)) ||
1127  (replaces = pjsip_param_find(&target_uri->other_param, &str_replaces))) {
1128  response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
1129  } else {
1130  response = refer_incoming_blind_request(session, rdata, target_uri, progress);
1131  }
1132 
1133  if (!progress) {
1134  /* The transferer has requested no subscription, so send a final response immediately */
1135  pjsip_tx_data *tdata;
1136  const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
1137  const pj_str_t str_false = { "false", 5 };
1138  pjsip_hdr *hdr;
1139 
1140  ast_debug(3, "Progress monitoring not requested for REFER on channel '%s' from endpoint '%s', sending immediate response of '%d'\n",
1141  ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), response);
1142 
1143  if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, response, NULL, &tdata) != PJ_SUCCESS) {
1144  pjsip_dlg_respond(session->inv_session->dlg, rdata, response, NULL, NULL, NULL);
1145  return 0;
1146  }
1147 
1148  hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
1149  pjsip_msg_add_hdr(tdata->msg, hdr);
1150 
1151  pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
1152  } else if (response != 200) {
1153  /* Since this failed we can send a final NOTIFY now and terminate the subscription */
1154  struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
1155 
1156  if (notification) {
1157  /* The refer_progress_notify function will call ao2_cleanup on this for us */
1158  refer_progress_notify(notification);
1159  }
1160  }
1161 
1162  return 0;
1163 }
1164 
1165 static int refer_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
1166 {
1167  if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
1168  return refer_incoming_refer_request(session, rdata);
1169  } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_invite_method)) {
1170  return refer_incoming_invite_request(session, rdata);
1171  } else {
1172  return 0;
1173  }
1174 }
1175 
1176 /*!
1177  * \brief Use the value of a channel variable as the value of a SIP header
1178  *
1179  * This looks up a variable name on a channel, then takes that value and adds
1180  * it to an outgoing SIP request. If the header already exists on the message,
1181  * then no action is taken.
1182  *
1183  * \pre chan is locked.
1184  *
1185  * \param chan The channel on which to find the variable.
1186  * \param var_name The name of the channel variable to use.
1187  * \param header_name The name of the SIP header to add to the outgoing message.
1188  * \param tdata The outgoing SIP message on which to add the header
1189  */
1190 static void add_header_from_channel_var(struct ast_channel *chan, const char *var_name, const char *header_name, pjsip_tx_data *tdata)
1191 {
1192  const char *var_value;
1193  pj_str_t pj_header_name;
1194  pjsip_hdr *header;
1195 
1196  var_value = pbx_builtin_getvar_helper(chan, var_name);
1197  if (ast_strlen_zero(var_value)) {
1198  return;
1199  }
1200 
1201  pj_cstr(&pj_header_name, header_name);
1202  header = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_header_name, NULL);
1203  if (header) {
1204  return;
1205  }
1206  ast_sip_add_header(tdata, header_name, var_value);
1207 }
1208 
1209 static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
1210 {
1211  if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method)
1212  || !session->channel
1213  || session->inv_session->state != PJSIP_INV_STATE_NULL) {
1214  return;
1215  }
1216 
1217  ast_channel_lock(session->channel);
1218  add_header_from_channel_var(session->channel, "SIPREPLACESHDR", "Replaces", tdata);
1219  add_header_from_channel_var(session->channel, "SIPREFERREDBYHDR", "Referred-By", tdata);
1220  ast_channel_unlock(session->channel);
1221 }
1222 
1225  .incoming_request = refer_incoming_request,
1226  .outgoing_request = refer_outgoing_request,
1227 };
1228 
1229 static int load_module(void)
1230 {
1231  const pj_str_t str_norefersub = { "norefersub", 10 };
1232 
1233  pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint());
1234  pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint());
1235 
1236  if (ast_sip_get_norefersub()) {
1237  pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub);
1238  }
1239 
1241  ast_sip_session_register_supplement(&refer_supplement);
1242 
1244 
1245  return AST_MODULE_LOAD_SUCCESS;
1246 }
1247 
1248 static int unload_module(void)
1249 {
1250  ast_sip_session_unregister_supplement(&refer_supplement);
1252 
1253  return 0;
1254 }
1255 
1256 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Blind and Attended Transfer Support",
1257  .support_level = AST_MODULE_SUPPORT_CORE,
1258  .load = load_module,
1259  .unload = unload_module,
1260  .load_pri = AST_MODPRI_APP_DEPEND,
1261  .requires = "res_pjsip,res_pjsip_session,res_pjsip_pubsub",
1262 );
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1146
pjsip_rx_data * rdata
Received packet, used to construct final response in case no subscription exists. ...
enum sip_cc_notify_state state
Definition: chan_sip.c:957
#define ast_channel_lock(chan)
Definition: channel.h:2890
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
struct ast_sip_endpoint * endpoint
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:2987
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
struct refer_progress * progress
Refer progress structure to send notification on.
int subclass
Last received subclass in frame hook.
struct ast_channel_snapshot_base * base
Asterisk main include file. File version handling, generic pbx functions.
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
Definition: bridge.c:4729
struct refer_progress * progress
Optional refer progress structure.
struct ast_sip_session * transferer
Transferer session.
struct ast_sip_session * transferer_second
Second transferer session.
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for channel enter bridge blob messages.
struct ast_channel_snapshot * channel
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2926
struct ast_taskprocessor * serializer
Serializer for notifications.
static struct ast_sip_session_supplement refer_supplement
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
unsigned int defer_terminate
pjsip_evsub * sub
Subscription to provide updates on.
struct stasis_subscription * bridge_sub
Stasis subscription for bridge events.
static void refer_progress_notification_destroy(void *obj)
Destructor for REFER Progress notification structure.
#define LOG_WARNING
Definition: logger.h:274
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.
struct transfer_channel_data * transfer_data
Reference to transfer_channel_data related to the refer.
ast_framehook_event
These are the types of events that the framehook&#39;s event callback can receive.
Definition: framehook.h:151
Structure used to retrieve channel from another session.
union ast_frame::@257 data
static int load_module(void)
Structure for blind transfer callback details.
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)
unsigned int ast_sip_get_norefersub(void)
Retrieve the global setting &#39;norefersub&#39;.
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
static int refer_incoming_refer_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Structure for attended transfer task.
static void refer_progress_bridge(void *data, struct stasis_subscription *sub, struct stasis_message *message)
static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int framehook
Frame hook for monitoring REFER progress.
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:1075
REFER Progress notification structure.
Definition: astman.c:222
static int defer_termination_cancel_task(void *data)
const ast_string_field uniqueid
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:650
unsigned int refer_blind_progress
Whether to notifies all the progress details on blind transfer.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
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:5125
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
Definition: pjsip_session.c:63
static void refer_attended_destroy(void *obj)
Destructor for attended transfer task.
#define NULL
Definition: resample.c:96
Definition: dsp.c:117
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:10724
ast_transfer_result
Definition: bridge.h:1115
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:60
struct pjsip_inv_session * inv_session
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:5089
static int refer_attended_task(void *data)
Task for attended transfer executed by attended->transferer_second serializer.
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_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
A structure describing a SIP session.
struct refer_progress * progress
Optional progress structure.
int ast_raw_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2685
unsigned int attended
Attended transfer flag.
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:4948
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_frame_subclass subclass
struct ast_bridge * bridge
Bridge the channel is in.
char * transferee
Uniqueid of transferee channel.
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
static pjsip_module refer_progress_module
REFER Progress module, used to attach REFER progress structure to subscriptions.
static int xfer_response_code2sip(enum ast_transfer_result xfer_code)
static int session_end_if_deferred_task(void *data)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
struct ast_bridge * ast_bridge_transfer_acquire_bridge(struct ast_channel *chan)
Acquire the channel&#39;s bridge for transfer purposes.
Definition: bridge.c:4460
const char * context
Context being used for transfer.
pjsip_sip_uri * refer_to
Optional Refer-To header.
struct ast_module * self
Definition: module.h:342
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:4477
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:1924
ast_transfer_type
Definition: bridge.h:1126
#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:851
static int refer_progress_terminate(void *data)
Serialized callback for subscription termination.
static struct ast_mansession session
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:5103
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.
#define AST_MAX_EXTENSION
Definition: channel.h:135
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2937
void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session)
Cancel a pending deferred termination.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2309
struct ast_channel * channel
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:4179
Blob of data associated with a bridge.
#define DETERMINE_TRANSFER_CONTEXT(context, session)
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:3217
static void refer_progress_destroy(void *obj)
Destructor for REFER progress sutrcture.
static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
Core PBX routines and definitions.
static int invite_replaces(void *data)
Task for invite replaces.
struct ast_taskprocessor * serializer
struct ast_sip_session * session
Session we want the channel from.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define AST_CAUSE_FAILURE
Definition: causes.h:149
Structure that contains information about a bridge.
Definition: bridge.h:357
#define LOG_ERROR
Definition: logger.h:285
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_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
Callback for REFER subscription state changes.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5023
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:464
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
pjsip_replaces_hdr * replaces
Optional Replaces header.
#define stasis_subscribe_pool(topic, callback, data)
Definition: stasis.h:682
enum ast_sip_supplement_priority priority
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:5018
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:969
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
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:1172
#define ast_strlen_zero(a)
Definition: muted.c:73
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...
#define ast_channel_unlock(chan)
Definition: channel.h:2891
#define ast_free(a)
Definition: astmm.h:182
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2534
unsigned int refer_blind_progress
Definition: res_pjsip.h:895
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.
unsigned int allowtransfer
Definition: res_pjsip.h:871
int response
SIP response code to send.
An API for managing task processing threads that can be shared across modules.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
A supplement to SIP message processing.
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...
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3614
static void refer_progress_framehook_destroy(void *data)
Destroy callback for monitoring framehook.
static pjsip_evsub_user refer_progress_evsub_cb
Callback structure for subscription.
FrameHook Architecture.
pjsip_rx_data * rdata
REFER message.
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
static int unload_module(void)
static int refer_progress_notify(void *data)
Serialized callback for subscription notification.
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2915
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_sip_session_end_if_deferred(struct ast_sip_session *session)
End the session if it had been previously deferred.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
const char * ast_channel_name(const struct ast_channel *chan)
static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target, struct refer_progress *progress)
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3233
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7349
AO2 object that wraps data for transfer_channel_cb.
Definition: bridge.h:1136
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:1021
Data structure associated with a single frame of data.
Internal Asterisk hangup causes.
pjsip_dialog * dlg
Dialog for subscription.
int error(const char *format,...)
Definition: utils/frame.c:999
int sent_100
Non-zero if the 100 notify has been sent.
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
enum ast_frame_type frametype
struct ast_channel * transferer_chan
Transferer channel.
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
pjsip_evsub_state state
Subscription state.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1450
Bridging API.
Asterisk module definitions.
REFER Progress structure.
struct ast_sip_session * ast_sip_dialog_get_session(pjsip_dialog *dlg)
Retrieves a session from a dialog.
struct ast_channel * channel
Channel from the session (with reference)
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.
#define ast_sip_session_register_supplement(supplement)