Asterisk - The Open Source Telephony Project  21.4.1
dialplan_functions.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  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16 
17 /*!
18  * \file
19  *
20  * \author \verbatim Joshua Colp <jcolp@digium.com> \endverbatim
21  * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
22  *
23  * \ingroup functions
24  *
25  * \brief PJSIP channel dialplan functions
26  */
27 
28 /*** MODULEINFO
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 #include <pjsip.h>
35 #include <pjlib.h>
36 #include <pjsip_ua.h>
37 
38 #include "asterisk/astobj2.h"
39 #include "asterisk/module.h"
40 #include "asterisk/acl.h"
41 #include "asterisk/app.h"
42 #include "asterisk/conversions.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/stream.h"
45 #include "asterisk/format.h"
46 #include "asterisk/dsp.h"
47 #include "asterisk/pbx.h"
48 #include "asterisk/res_pjsip.h"
49 #include "asterisk/res_pjsip_session.h"
50 #include "include/chan_pjsip.h"
52 
53 /*!
54  * \brief String representations of the T.38 state enum
55  */
56 static const char *t38state_to_string[T38_MAX_ENUM] = {
57  [T38_DISABLED] = "DISABLED",
58  [T38_LOCAL_REINVITE] = "LOCAL_REINVITE",
59  [T38_PEER_REINVITE] = "REMOTE_REINVITE",
60  [T38_ENABLED] = "ENABLED",
61  [T38_REJECTED] = "REJECTED",
62 };
63 
64 /*!
65  * \internal \brief Handle reading RTP information
66  */
67 static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
68 {
69  struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
70  struct ast_sip_session *session;
71  struct ast_sip_session_media *media;
72  struct ast_sockaddr addr;
73 
74  if (!channel) {
75  ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
76  return -1;
77  }
78 
79  session = channel->session;
80  if (!session) {
81  ast_log(AST_LOG_WARNING, "Channel %s has no session!\n", ast_channel_name(chan));
82  return -1;
83  }
84 
85  if (ast_strlen_zero(type)) {
86  ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtp' information\n");
87  return -1;
88  }
89 
90  if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
91  media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
92  } else if (!strcmp(field, "video")) {
93  media = session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO];
94  } else {
95  ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field);
96  return -1;
97  }
98 
99  if (!media || !media->rtp) {
100  ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
101  ast_channel_name(chan), S_OR(field, "audio"));
102  return -1;
103  }
104 
105  if (!strcmp(type, "src")) {
107  ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen);
108  } else if (!strcmp(type, "dest")) {
110  ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen);
111  } else if (!strcmp(type, "direct")) {
113  } else if (!strcmp(type, "secure")) {
114  if (media->srtp) {
115  struct ast_sdp_srtp *srtp = media->srtp;
116  int flag = ast_test_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK);
117  snprintf(buf, buflen, "%d", flag ? 1 : 0);
118  } else {
119  snprintf(buf, buflen, "%d", 0);
120  }
121  } else if (!strcmp(type, "hold")) {
122  snprintf(buf, buflen, "%d", media->remotely_held ? 1 : 0);
123  } else {
124  ast_log(AST_LOG_WARNING, "Unknown type field '%s' specified for 'rtp' information\n", type);
125  return -1;
126  }
127 
128  return 0;
129 }
130 
131 /*!
132  * \internal \brief Handle reading RTCP information
133  */
134 static int channel_read_rtcp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
135 {
136  struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
137  struct ast_sip_session *session;
138  struct ast_sip_session_media *media;
139 
140  if (!channel) {
141  ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
142  return -1;
143  }
144 
145  session = channel->session;
146  if (!session) {
147  ast_log(AST_LOG_WARNING, "Channel %s has no session!\n", ast_channel_name(chan));
148  return -1;
149  }
150 
151  if (ast_strlen_zero(type)) {
152  ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtcp' information\n");
153  return -1;
154  }
155 
156  if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
157  media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
158  } else if (!strcmp(field, "video")) {
159  media = session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO];
160  } else {
161  ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtcp' information\n", field);
162  return -1;
163  }
164 
165  if (!media || !media->rtp) {
166  ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
167  ast_channel_name(chan), S_OR(field, "audio"));
168  return -1;
169  }
170 
171  if (!strncasecmp(type, "all", 3)) {
173 
174  if (!strcasecmp(type, "all_jitter")) {
176  } else if (!strcasecmp(type, "all_rtt")) {
178  } else if (!strcasecmp(type, "all_loss")) {
180  } else if (!strcasecmp(type, "all_mes")) {
182  }
183 
184  if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {
185  ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
186  return -1;
187  }
188  } else {
189  struct ast_rtp_instance_stats stats;
190  int i;
191  struct {
192  const char *name;
193  enum { INT, DBL } type;
194  union {
195  unsigned int *i4;
196  double *d8;
197  };
198  } lookup[] = {
199  { "txcount", INT, { .i4 = &stats.txcount, }, },
200  { "rxcount", INT, { .i4 = &stats.rxcount, }, },
201  { "txjitter", DBL, { .d8 = &stats.txjitter, }, },
202  { "rxjitter", DBL, { .d8 = &stats.rxjitter, }, },
203  { "remote_maxjitter", DBL, { .d8 = &stats.remote_maxjitter, }, },
204  { "remote_minjitter", DBL, { .d8 = &stats.remote_minjitter, }, },
205  { "remote_normdevjitter", DBL, { .d8 = &stats.remote_normdevjitter, }, },
206  { "remote_stdevjitter", DBL, { .d8 = &stats.remote_stdevjitter, }, },
207  { "local_maxjitter", DBL, { .d8 = &stats.local_maxjitter, }, },
208  { "local_minjitter", DBL, { .d8 = &stats.local_minjitter, }, },
209  { "local_normdevjitter", DBL, { .d8 = &stats.local_normdevjitter, }, },
210  { "local_stdevjitter", DBL, { .d8 = &stats.local_stdevjitter, }, },
211  { "txploss", INT, { .i4 = &stats.txploss, }, },
212  { "rxploss", INT, { .i4 = &stats.rxploss, }, },
213  { "remote_maxrxploss", DBL, { .d8 = &stats.remote_maxrxploss, }, },
214  { "remote_minrxploss", DBL, { .d8 = &stats.remote_minrxploss, }, },
215  { "remote_normdevrxploss", DBL, { .d8 = &stats.remote_normdevrxploss, }, },
216  { "remote_stdevrxploss", DBL, { .d8 = &stats.remote_stdevrxploss, }, },
217  { "local_maxrxploss", DBL, { .d8 = &stats.local_maxrxploss, }, },
218  { "local_minrxploss", DBL, { .d8 = &stats.local_minrxploss, }, },
219  { "local_normdevrxploss", DBL, { .d8 = &stats.local_normdevrxploss, }, },
220  { "local_stdevrxploss", DBL, { .d8 = &stats.local_stdevrxploss, }, },
221  { "rtt", DBL, { .d8 = &stats.rtt, }, },
222  { "maxrtt", DBL, { .d8 = &stats.maxrtt, }, },
223  { "minrtt", DBL, { .d8 = &stats.minrtt, }, },
224  { "normdevrtt", DBL, { .d8 = &stats.normdevrtt, }, },
225  { "stdevrtt", DBL, { .d8 = &stats.stdevrtt, }, },
226  { "local_ssrc", INT, { .i4 = &stats.local_ssrc, }, },
227  { "remote_ssrc", INT, { .i4 = &stats.remote_ssrc, }, },
228  { "txmes", DBL, { .d8 = &stats.txmes, }, },
229  { "rxmes", DBL, { .d8 = &stats.rxmes, }, },
230  { "remote_maxmes", DBL, { .d8 = &stats.remote_maxmes, }, },
231  { "remote_minmes", DBL, { .d8 = &stats.remote_minmes, }, },
232  { "remote_normdevmes", DBL, { .d8 = &stats.remote_normdevmes, }, },
233  { "remote_stdevmes", DBL, { .d8 = &stats.remote_stdevmes, }, },
234  { "local_maxmes", DBL, { .d8 = &stats.local_maxmes, }, },
235  { "local_minmes", DBL, { .d8 = &stats.local_minmes, }, },
236  { "local_normdevmes", DBL, { .d8 = &stats.local_normdevmes, }, },
237  { "local_stdevmes", DBL, { .d8 = &stats.local_stdevmes, }, },
238  { NULL, },
239  };
240 
242  ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
243  return -1;
244  }
245 
246  for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
247  if (!strcasecmp(type, lookup[i].name)) {
248  if (lookup[i].type == INT) {
249  snprintf(buf, buflen, "%u", *lookup[i].i4);
250  } else {
251  snprintf(buf, buflen, "%f", *lookup[i].d8);
252  }
253  return 0;
254  }
255  }
256  ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'rtcp' information\n", type);
257  return -1;
258  }
259 
260  return 0;
261 }
262 
263 static int print_escaped_uri(struct ast_channel *chan, const char *type,
264  pjsip_uri_context_e context, const void *uri, char *buf, size_t size)
265 {
266  int res;
267  char *buf_copy;
268 
269  res = pjsip_uri_print(context, uri, buf, size);
270  if (res < 0) {
271  ast_log(LOG_ERROR, "Channel %s: Unescaped %s too long for %d byte buffer\n",
272  ast_channel_name(chan), type, (int) size);
273 
274  /* Empty buffer that likely is not terminated. */
275  buf[0] = '\0';
276  return -1;
277  }
278 
279  buf_copy = ast_strdupa(buf);
280  ast_escape_quoted(buf_copy, buf, size);
281  return 0;
282 }
283 
284 /*!
285  * \internal \brief Handle reading signalling information
286  */
287 static int channel_read_pjsip(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
288 {
289  struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
290  char *buf_copy;
291  pjsip_dialog *dlg;
292  int res = 0;
293 
294  if (!channel) {
295  ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
296  return -1;
297  }
298 
299  dlg = channel->session->inv_session->dlg;
300 
301  if (ast_strlen_zero(type)) {
302  ast_log(LOG_WARNING, "You must supply a type field for 'pjsip' information\n");
303  return -1;
304  } else if (!strcmp(type, "call-id")) {
305  snprintf(buf, buflen, "%.*s", (int) pj_strlen(&dlg->call_id->id), pj_strbuf(&dlg->call_id->id));
306  } else if (!strcmp(type, "secure")) {
307 #ifdef HAVE_PJSIP_GET_DEST_INFO
308  pjsip_host_info dest;
309  pj_pool_t *pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "secure-check", 128, 128);
310  pjsip_get_dest_info(dlg->target, NULL, pool, &dest);
311  snprintf(buf, buflen, "%d", dest.flag & PJSIP_TRANSPORT_SECURE ? 1 : 0);
312  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
313 #else
314  ast_log(LOG_WARNING, "Asterisk has been built against a version of pjproject which does not have the required functionality to support the 'secure' argument. Please upgrade to version 2.3 or later.\n");
315  return -1;
316 #endif
317  } else if (!strcmp(type, "target_uri")) {
318  res = print_escaped_uri(chan, type, PJSIP_URI_IN_REQ_URI, dlg->target, buf,
319  buflen);
320  } else if (!strcmp(type, "local_uri")) {
321  res = print_escaped_uri(chan, type, PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri,
322  buf, buflen);
323  } else if (!strcmp(type, "local_tag")) {
324  ast_copy_pj_str(buf, &dlg->local.info->tag, buflen);
325  buf_copy = ast_strdupa(buf);
326  ast_escape_quoted(buf_copy, buf, buflen);
327  } else if (!strcmp(type, "remote_uri")) {
328  res = print_escaped_uri(chan, type, PJSIP_URI_IN_FROMTO_HDR,
329  dlg->remote.info->uri, buf, buflen);
330  } else if (!strcmp(type, "remote_tag")) {
331  ast_copy_pj_str(buf, &dlg->remote.info->tag, buflen);
332  buf_copy = ast_strdupa(buf);
333  ast_escape_quoted(buf_copy, buf, buflen);
334  } else if (!strcmp(type, "request_uri")) {
335  if (channel->session->request_uri) {
336  res = print_escaped_uri(chan, type, PJSIP_URI_IN_REQ_URI,
337  channel->session->request_uri, buf, buflen);
338  }
339  } else if (!strcmp(type, "t38state")) {
340  ast_copy_string(buf, t38state_to_string[channel->session->t38state], buflen);
341  } else if (!strcmp(type, "local_addr")) {
342  RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
343  struct transport_info_data *transport_data;
344 
345  datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
346  if (!datastore) {
347  ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
348  return -1;
349  }
350  transport_data = datastore->data;
351 
352  if (pj_sockaddr_has_addr(&transport_data->local_addr)) {
353  pj_sockaddr_print(&transport_data->local_addr, buf, buflen, 3);
354  }
355  } else if (!strcmp(type, "remote_addr")) {
356  RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
357  struct transport_info_data *transport_data;
358 
359  datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
360  if (!datastore) {
361  ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
362  return -1;
363  }
364  transport_data = datastore->data;
365 
366  if (pj_sockaddr_has_addr(&transport_data->remote_addr)) {
367  pj_sockaddr_print(&transport_data->remote_addr, buf, buflen, 3);
368  }
369  } else {
370  ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'pjsip' information\n", type);
371  return -1;
372  }
373 
374  return res;
375 }
376 
377 /*! \brief Struct used to push function arguments to task processor */
379  struct ast_sip_session *session;
380  const char *param;
381  const char *type;
382  const char *field;
383  char *buf;
384  size_t len;
385  int ret;
386 };
387 
388 /*! \internal \brief Taskprocessor callback that handles the read on a PJSIP thread */
389 static int read_pjsip(void *data)
390 {
391  struct pjsip_func_args *func_args = data;
392 
393  if (!strcmp(func_args->param, "rtp")) {
394  if (!func_args->session->channel) {
395  func_args->ret = -1;
396  return 0;
397  }
398  func_args->ret = channel_read_rtp(func_args->session->channel, func_args->type,
399  func_args->field, func_args->buf,
400  func_args->len);
401  } else if (!strcmp(func_args->param, "rtcp")) {
402  if (!func_args->session->channel) {
403  func_args->ret = -1;
404  return 0;
405  }
406  func_args->ret = channel_read_rtcp(func_args->session->channel, func_args->type,
407  func_args->field, func_args->buf,
408  func_args->len);
409  } else if (!strcmp(func_args->param, "endpoint")) {
410  if (!func_args->session->endpoint) {
411  ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", func_args->session->channel ?
412  ast_channel_name(func_args->session->channel) : "<unknown>");
413  func_args->ret = -1;
414  return 0;
415  }
416  snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->endpoint));
417  } else if (!strcmp(func_args->param, "contact")) {
418  if (!func_args->session->contact) {
419  return 0;
420  }
421  snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->contact));
422  } else if (!strcmp(func_args->param, "aor")) {
423  if (!func_args->session->aor) {
424  return 0;
425  }
426  snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->aor));
427  } else if (!strcmp(func_args->param, "pjsip")) {
428  if (!func_args->session->channel) {
429  func_args->ret = -1;
430  return 0;
431  }
432  func_args->ret = channel_read_pjsip(func_args->session->channel, func_args->type,
433  func_args->field, func_args->buf,
434  func_args->len);
435  } else {
436  func_args->ret = -1;
437  }
438 
439  return 0;
440 }
441 
442 
443 int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
444 {
445  struct pjsip_func_args func_args = { 0, };
446  struct ast_sip_channel_pvt *channel;
447  char *parse = ast_strdupa(data);
448 
450  AST_APP_ARG(param);
451  AST_APP_ARG(type);
452  AST_APP_ARG(field);
453  );
454 
455  if (!chan) {
456  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
457  return -1;
458  }
459 
460  /* Check for zero arguments */
461  if (ast_strlen_zero(parse)) {
462  ast_log(LOG_ERROR, "Cannot call %s without arguments\n", cmd);
463  return -1;
464  }
465 
466  AST_STANDARD_APP_ARGS(args, parse);
467 
468  ast_channel_lock(chan);
469 
470  /* Sanity check */
471  if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
472  ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
473  ast_channel_unlock(chan);
474  return 0;
475  }
476 
477  channel = ast_channel_tech_pvt(chan);
478  if (!channel) {
479  ast_log(LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
480  ast_channel_unlock(chan);
481  return -1;
482  }
483 
484  if (!channel->session) {
485  ast_log(LOG_WARNING, "Channel %s has no session\n", ast_channel_name(chan));
486  ast_channel_unlock(chan);
487  return -1;
488  }
489 
490  func_args.session = ao2_bump(channel->session);
491  ast_channel_unlock(chan);
492 
493  memset(buf, 0, len);
494 
495  func_args.param = args.param;
496  func_args.type = args.type;
497  func_args.field = args.field;
498  func_args.buf = buf;
499  func_args.len = len;
500  if (ast_sip_push_task_wait_serializer(func_args.session->serializer, read_pjsip, &func_args)) {
501  ast_log(LOG_WARNING, "Unable to read properties of channel %s: failed to push task\n", ast_channel_name(chan));
502  ao2_ref(func_args.session, -1);
503  return -1;
504  }
505  ao2_ref(func_args.session, -1);
506 
507  return func_args.ret;
508 }
509 
510 int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
511 {
512  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
513  RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
514  const char *aor_name;
515  char *rest;
516 
518  AST_APP_ARG(endpoint_name);
519  AST_APP_ARG(aor_name);
520  AST_APP_ARG(request_user);
521  );
522 
523  AST_STANDARD_APP_ARGS(args, data);
524 
525  if (ast_strlen_zero(args.endpoint_name)) {
526  ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
527  return -1;
528  } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
529  ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
530  return -1;
531  }
532 
533  aor_name = S_OR(args.aor_name, endpoint->aors);
534 
535  if (ast_strlen_zero(aor_name)) {
536  ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
537  return -1;
538  } else if (!(dial = ast_str_create(len))) {
539  ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
540  return -1;
541  } else if (!(rest = ast_strdupa(aor_name))) {
542  ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
543  return -1;
544  }
545 
546  while ((aor_name = ast_strip(strsep(&rest, ",")))) {
547  RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
548  RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
549  struct ao2_iterator it_contacts;
550  struct ast_sip_contact *contact;
551 
552  if (!aor) {
553  /* If the AOR provided is not found skip it, there may be more */
554  continue;
555  } else if (!(contacts = ast_sip_location_retrieve_aor_contacts_filtered(aor, AST_SIP_CONTACT_FILTER_REACHABLE))) {
556  /* No contacts are available, skip it as well */
557  continue;
558  } else if (!ao2_container_count(contacts)) {
559  /* We were given a container but no contacts are in it... */
560  continue;
561  }
562 
563  it_contacts = ao2_iterator_init(contacts, 0);
564  for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
565  ast_str_append(&dial, -1, "PJSIP/");
566 
567  if (!ast_strlen_zero(args.request_user)) {
568  ast_str_append(&dial, -1, "%s@", args.request_user);
569  }
570  ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
571  }
572  ao2_iterator_destroy(&it_contacts);
573  }
574 
575  /* Trim the '&' at the end off */
576  ast_str_truncate(dial, ast_str_strlen(dial) - 1);
577 
578  ast_copy_string(buf, ast_str_buffer(dial), len);
579 
580  return 0;
581 }
582 
583 /*! \brief Session refresh state information */
585  /*! \brief Created proposed media state */
587 };
588 
589 /*! \brief Destructor for session refresh information */
590 static void session_refresh_state_destroy(void *obj)
591 {
592  struct session_refresh_state *state = obj;
593 
594  ast_sip_session_media_state_free(state->media_state);
595  ast_free(obj);
596 }
597 
598 /*! \brief Datastore for attaching session refresh state information */
600  .type = "pjsip_session_refresh",
602 };
603 
604 /*! \brief Helper function which retrieves or allocates a session refresh state information datastore */
606 {
607  RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "pjsip_session_refresh"), ao2_cleanup);
609 
610  /* While the datastore refcount is decremented this is operating in the serializer so it will remain valid regardless */
611  if (datastore) {
612  return datastore->data;
613  }
614 
615  if (!(datastore = ast_sip_session_alloc_datastore(&session_refresh_datastore, "pjsip_session_refresh"))
616  || !(datastore->data = ast_calloc(1, sizeof(struct session_refresh_state)))
617  || ast_sip_session_add_datastore(session, datastore)) {
618  return NULL;
619  }
620 
621  state = datastore->data;
622  state->media_state = ast_sip_session_media_state_alloc();
623  if (!state->media_state) {
624  ast_sip_session_remove_datastore(session, "pjsip_session_refresh");
625  return NULL;
626  }
628  if (!state->media_state->topology) {
629  ast_sip_session_remove_datastore(session, "pjsip_session_refresh");
630  return NULL;
631  }
632 
633  datastore->data = state;
634 
635  return state;
636 }
637 
638 /*! \brief Struct used to push PJSIP_PARSE_URI function arguments to task processor */
640  const char *uri;
641  const char *type;
642  char *buf;
643  size_t buflen;
644  int ret;
645 };
646 
647 /*! \internal \brief Taskprocessor callback that handles the PJSIP_PARSE_URI on a PJSIP thread */
648 static int parse_uri_cb(void *data)
649 {
650  struct parse_uri_args *args = data;
651  pj_pool_t *pool;
652  pjsip_name_addr *uri;
653  pjsip_sip_uri *sip_uri;
654  pj_str_t tmp;
655 
656  args->ret = 0;
657 
658  pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "ParseUri", 128, 128);
659  if (!pool) {
660  ast_log(LOG_ERROR, "Failed to allocate ParseUri endpoint pool.\n");
661  args->ret = -1;
662  return 0;
663  }
664 
665  pj_strdup2_with_null(pool, &tmp, args->uri);
666  uri = (pjsip_name_addr *)pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
667  if (!uri || (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
668  ast_log(LOG_WARNING, "Failed to parse URI '%s'\n", args->uri);
669  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
670  args->ret = -1;
671  return 0;
672  }
673 
674  if (!strcmp(args->type, "scheme")) {
675  ast_copy_pj_str(args->buf, pjsip_uri_get_scheme(uri), args->buflen);
676  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
677  return 0;
678  } else if (!strcmp(args->type, "display")) {
679  ast_copy_pj_str(args->buf, &uri->display, args->buflen);
680  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
681  return 0;
682  }
683 
684  sip_uri = pjsip_uri_get_uri(uri);
685  if (!sip_uri) {
686  ast_log(LOG_ERROR, "Failed to get an URI object for '%s'\n", args->uri);
687  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
688  args->ret = -1;
689  return 0;
690  }
691 
692  if (!strcmp(args->type, "user")) {
693  ast_copy_pj_str(args->buf, &sip_uri->user, args->buflen);
694  } else if (!strcmp(args->type, "passwd")) {
695  ast_copy_pj_str(args->buf, &sip_uri->passwd, args->buflen);
696  } else if (!strcmp(args->type, "host")) {
697  ast_copy_pj_str(args->buf, &sip_uri->host, args->buflen);
698  } else if (!strcmp(args->type, "port")) {
699  snprintf(args->buf, args->buflen, "%d", sip_uri->port);
700  } else if (!strcmp(args->type, "user_param")) {
701  ast_copy_pj_str(args->buf, &sip_uri->user_param, args->buflen);
702  } else if (!strcmp(args->type, "method_param")) {
703  ast_copy_pj_str(args->buf, &sip_uri->method_param, args->buflen);
704  } else if (!strcmp(args->type, "transport_param")) {
705  ast_copy_pj_str(args->buf, &sip_uri->transport_param, args->buflen);
706  } else if (!strcmp(args->type, "ttl_param")) {
707  snprintf(args->buf, args->buflen, "%d", sip_uri->ttl_param);
708  } else if (!strcmp(args->type, "lr_param")) {
709  snprintf(args->buf, args->buflen, "%d", sip_uri->lr_param);
710  } else if (!strcmp(args->type, "maddr_param")) {
711  ast_copy_pj_str(args->buf, &sip_uri->maddr_param, args->buflen);
712  } else {
713  ast_log(AST_LOG_WARNING, "Unknown type part '%s' specified\n", args->type);
714  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
715  args->ret = -1;
716  return 0;
717  }
718 
719  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
720 
721  return 0;
722 }
723 
724 int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
725 {
726  struct parse_uri_args func_args = { 0, };
727  int reading_uri_from_var;
728 
730  AST_APP_ARG(uri_str);
731  AST_APP_ARG(type);
732  );
733 
734  AST_STANDARD_APP_ARGS(args, data);
735 
736  reading_uri_from_var = !strcasecmp(cmd, "PJSIP_PARSE_URI_FROM");
737 
738  if (reading_uri_from_var) {
739  const char *var;
740 
741  if (ast_strlen_zero(args.uri_str)) {
742  ast_log(LOG_WARNING, "The name of a variable containing a URI must be specified when using the '%s' dialplan function\n", cmd);
743  return -1;
744  }
745 
746  ast_channel_lock(chan);
747  if ((var = pbx_builtin_getvar_helper(chan, args.uri_str))) {
748  args.uri_str = ast_strdupa(var);
749  }
750  ast_channel_unlock(chan);
751  }
752 
753  if (ast_strlen_zero(args.uri_str)) {
754  if (reading_uri_from_var) {
755  ast_log(LOG_WARNING, "The variable provided to the '%s' dialplan function must contain a URI\n", cmd);
756  } else {
757  ast_log(LOG_WARNING, "A URI must be specified when using the '%s' dialplan function\n", cmd);
758  }
759  return -1;
760  }
761 
762  if (ast_strlen_zero(args.type)) {
763  ast_log(LOG_WARNING, "A type part of the URI must be specified when using the '%s' dialplan function\n", cmd);
764  return -1;
765  }
766 
767  memset(buf, 0, buflen);
768 
769  func_args.uri = args.uri_str;
770  func_args.type = args.type;
771  func_args.buf = buf;
772  func_args.buflen = buflen;
773  if (ast_sip_push_task_wait_serializer(NULL, parse_uri_cb, &func_args)) {
774  ast_log(LOG_WARNING, "Unable to parse URI: failed to push task\n");
775  return -1;
776  }
777 
778  return func_args.ret;
779 }
780 
781 static int media_offer_read_av(struct ast_sip_session *session, char *buf,
782  size_t len, enum ast_media_type media_type)
783 {
784  struct ast_stream_topology *topology;
785  int idx;
786  struct ast_stream *stream = NULL;
787  const struct ast_format_cap *caps;
788  size_t accum = 0;
789 
790  if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
792 
793  /* As we've already answered we need to store our media state until we are ready to send it */
794  state = session_refresh_state_get_or_alloc(session);
795  if (!state) {
796  return -1;
797  }
798  topology = state->media_state->topology;
799  } else {
800  /* The session is not yet up so we are initially answering or offering */
801  if (!session->pending_media_state->topology) {
803  if (!session->pending_media_state->topology) {
804  return -1;
805  }
806  }
807  topology = session->pending_media_state->topology;
808  }
809 
810  /* Find the first suitable stream */
811  for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) {
812  stream = ast_stream_topology_get_stream(topology, idx);
813 
814  if (ast_stream_get_type(stream) != media_type ||
816  stream = NULL;
817  continue;
818  }
819 
820  break;
821  }
822 
823  /* If no suitable stream then exit early */
824  if (!stream) {
825  buf[0] = '\0';
826  return 0;
827  }
828 
829  caps = ast_stream_get_formats(stream);
830 
831  /* Note: buf is not terminated while the string is being built. */
832  for (idx = 0; idx < ast_format_cap_count(caps); ++idx) {
833  struct ast_format *fmt;
834  size_t size;
835 
836  fmt = ast_format_cap_get_format(caps, idx);
837 
838  /* Add one for a comma or terminator */
839  size = strlen(ast_format_get_name(fmt)) + 1;
840  if (len < size) {
841  ao2_ref(fmt, -1);
842  break;
843  }
844 
845  /* Append the format name */
846  strcpy(buf + accum, ast_format_get_name(fmt));/* Safe */
847  ao2_ref(fmt, -1);
848 
849  accum += size;
850  len -= size;
851 
852  /* The last comma on the built string will be set to the terminator. */
853  buf[accum - 1] = ',';
854  }
855 
856  /* Remove the trailing comma or terminate an empty buffer. */
857  buf[accum ? accum - 1 : 0] = '\0';
858  return 0;
859 }
860 
862  struct ast_sip_session *session;
863  enum ast_media_type media_type;
864  const char *value;
865 };
866 
867 static int media_offer_write_av(void *obj)
868 {
869  struct media_offer_data *data = obj;
870  struct ast_stream_topology *topology;
871  struct ast_stream *stream;
872  struct ast_format_cap *caps;
873 
874  if (data->session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
875  struct session_refresh_state *state;
876 
877  /* As we've already answered we need to store our media state until we are ready to send it */
878  state = session_refresh_state_get_or_alloc(data->session);
879  if (!state) {
880  return -1;
881  }
882  topology = state->media_state->topology;
883  } else {
884  /* The session is not yet up so we are initially answering or offering */
885  if (!data->session->pending_media_state->topology) {
887  if (!data->session->pending_media_state->topology) {
888  return -1;
889  }
890  }
891  topology = data->session->pending_media_state->topology;
892  }
893 
894  /* XXX This method won't work when it comes time to do multistream support. The proper way to do this
895  * will either be to
896  * a) Alter all media streams of a particular type.
897  * b) Change the dialplan function to be able to specify which stream to alter and alter only that
898  * one stream
899  */
900  stream = ast_stream_topology_get_first_stream_by_type(topology, data->media_type);
901  if (!stream) {
902  return 0;
903  }
904 
906  if (!caps) {
907  return -1;
908  }
909 
911  AST_MEDIA_TYPE_UNKNOWN);
912  ast_format_cap_remove_by_type(caps, data->media_type);
913  ast_format_cap_update_by_allow_disallow(caps, data->value, 1);
914  ast_stream_set_formats(stream, caps);
915  ast_stream_set_metadata(stream, "pjsip_session_refresh", "force");
916  ao2_ref(caps, -1);
917 
918  return 0;
919 }
920 
921 int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
922 {
923  struct ast_sip_channel_pvt *channel;
924 
925  if (!chan) {
926  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
927  return -1;
928  }
929 
930  if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
931  ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
932  return -1;
933  }
934 
935  channel = ast_channel_tech_pvt(chan);
936 
937  if (!strcmp(data, "audio")) {
938  return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_AUDIO);
939  } else if (!strcmp(data, "video")) {
940  return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_VIDEO);
941  } else {
942  /* Ensure that the buffer is empty */
943  buf[0] = '\0';
944  }
945 
946  return 0;
947 }
948 
949 int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
950 {
951  struct ast_sip_channel_pvt *channel;
952  struct media_offer_data mdata = {
953  .value = value
954  };
955 
956  if (!chan) {
957  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
958  return -1;
959  }
960 
961  if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
962  ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
963  return -1;
964  }
965 
966  channel = ast_channel_tech_pvt(chan);
967  mdata.session = channel->session;
968 
969  if (!strcmp(data, "audio")) {
970  mdata.media_type = AST_MEDIA_TYPE_AUDIO;
971  } else if (!strcmp(data, "video")) {
972  mdata.media_type = AST_MEDIA_TYPE_VIDEO;
973  }
974 
975  return ast_sip_push_task_wait_serializer(channel->session->serializer, media_offer_write_av, &mdata);
976 }
977 
978 int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
979 {
980  struct ast_sip_channel_pvt *channel;
981 
982  if (!chan) {
983  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
984  return -1;
985  }
986 
987  ast_channel_lock(chan);
988  if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
989  ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
990  ast_channel_unlock(chan);
991  return -1;
992  }
993 
994  channel = ast_channel_tech_pvt(chan);
995 
996  if (ast_sip_dtmf_to_str(channel->session->dtmf, buf, len) < 0) {
997  ast_log(LOG_WARNING, "Unknown DTMF mode %d on PJSIP channel %s\n", channel->session->dtmf, ast_channel_name(chan));
998  ast_channel_unlock(chan);
999  return -1;
1000  }
1001 
1002  ast_channel_unlock(chan);
1003  return 0;
1004 }
1005 
1006 int pjsip_acf_moh_passthrough_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1007 {
1008  struct ast_sip_channel_pvt *channel;
1009 
1010  if (!chan) {
1011  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1012  return -1;
1013  }
1014 
1015  if (len < 3) {
1016  ast_log(LOG_WARNING, "%s: buffer too small\n", cmd);
1017  return -1;
1018  }
1019 
1020  ast_channel_lock(chan);
1021  if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1022  ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1023  ast_channel_unlock(chan);
1024  return -1;
1025  }
1026 
1027  channel = ast_channel_tech_pvt(chan);
1028  strncpy(buf, AST_YESNO(channel->session->moh_passthrough), len);
1029 
1030  ast_channel_unlock(chan);
1031  return 0;
1032 }
1033 
1035  struct ast_sip_session *session;
1036  enum ast_sip_session_refresh_method method;
1037 };
1038 
1039 static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
1040 {
1041  struct ast_format *fmt;
1042 
1043  if (!session->channel) {
1044  /* Egads! */
1045  return 0;
1046  }
1047 
1048  fmt = ast_format_cap_get_best_by_type(ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_AUDIO);
1049  if (!fmt) {
1050  /* No format? That's weird. */
1051  return 0;
1052  }
1053  ast_channel_set_writeformat(session->channel, fmt);
1054  ast_channel_set_rawwriteformat(session->channel, fmt);
1055  ast_channel_set_readformat(session->channel, fmt);
1056  ast_channel_set_rawreadformat(session->channel, fmt);
1057  ao2_ref(fmt, -1);
1058 
1059  return 0;
1060 }
1061 
1062 static int dtmf_mode_refresh_cb(void *obj)
1063 {
1064  struct refresh_data *data = obj;
1065 
1066  if (data->session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) {
1067  ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSWER completion. Sending session refresh\n", ast_channel_name(data->session->channel));
1068 
1069  ast_sip_session_refresh(data->session, NULL, NULL,
1070  sip_session_response_cb, data->method, 1, NULL);
1071  } else if (data->session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
1072  ast_debug(3, "Changing DTMF mode on channel %s during OFFER/ANSWER exchange. Updating SDP answer\n", ast_channel_name(data->session->channel));
1073  ast_sip_session_regenerate_answer(data->session, NULL);
1074  }
1075 
1076  return 0;
1077 }
1078 
1079 int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1080 {
1081  struct ast_sip_channel_pvt *channel;
1082  struct ast_sip_session_media *media;
1083  int dsp_features = 0;
1084  int dtmf = -1;
1085  struct refresh_data rdata = {
1086  .method = AST_SIP_SESSION_REFRESH_METHOD_INVITE,
1087  };
1088 
1089  if (!chan) {
1090  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1091  return -1;
1092  }
1093 
1094  ast_channel_lock(chan);
1095  if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1096  ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1097  ast_channel_unlock(chan);
1098  return -1;
1099  }
1100 
1101  channel = ast_channel_tech_pvt(chan);
1102  rdata.session = channel->session;
1103 
1104  dtmf = ast_sip_str_to_dtmf(value);
1105 
1106  if (dtmf == -1) {
1107  ast_log(LOG_WARNING, "Cannot set DTMF mode to '%s' on channel '%s' as value is invalid.\n", value,
1108  ast_channel_name(chan));
1109  ast_channel_unlock(chan);
1110  return -1;
1111  }
1112 
1113  if (channel->session->dtmf == dtmf) {
1114  /* DTMF mode unchanged, nothing to do! */
1115  ast_channel_unlock(chan);
1116  return 0;
1117  }
1118 
1119  channel->session->dtmf = dtmf;
1120 
1121  media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
1122 
1123  if (media && media->rtp) {
1124  if (channel->session->dtmf == AST_SIP_DTMF_RFC_4733) {
1127  } else if (channel->session->dtmf == AST_SIP_DTMF_INFO) {
1130  } else if (channel->session->dtmf == AST_SIP_DTMF_INBAND) {
1133  } else if (channel->session->dtmf == AST_SIP_DTMF_NONE) {
1136  } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO) {
1138  /* no RFC4733 negotiated, enable inband */
1140  }
1141  } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO_INFO) {
1144  /* if inband, switch to INFO */
1146  }
1147  }
1148  }
1149 
1150  if (channel->session->dsp) {
1151  dsp_features = ast_dsp_get_features(channel->session->dsp);
1152  }
1153  if (channel->session->dtmf == AST_SIP_DTMF_INBAND ||
1154  channel->session->dtmf == AST_SIP_DTMF_AUTO) {
1155  dsp_features |= DSP_FEATURE_DIGIT_DETECT;
1156  } else {
1157  dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
1158  }
1159  if (dsp_features) {
1160  if (!channel->session->dsp) {
1161  if (!(channel->session->dsp = ast_dsp_new())) {
1162  ast_channel_unlock(chan);
1163  return 0;
1164  }
1165  }
1166  ast_dsp_set_features(channel->session->dsp, dsp_features);
1167  } else if (channel->session->dsp) {
1168  ast_dsp_free(channel->session->dsp);
1169  channel->session->dsp = NULL;
1170  }
1171 
1172  ast_channel_unlock(chan);
1173 
1174  return ast_sip_push_task_wait_serializer(channel->session->serializer, dtmf_mode_refresh_cb, &rdata);
1175 }
1176 
1177 int pjsip_acf_moh_passthrough_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1178 {
1179  struct ast_sip_channel_pvt *channel;
1180 
1181  if (!chan) {
1182  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1183  return -1;
1184  }
1185 
1186  ast_channel_lock(chan);
1187  if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1188  ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1189  ast_channel_unlock(chan);
1190  return -1;
1191  }
1192 
1193  channel = ast_channel_tech_pvt(chan);
1194  channel->session->moh_passthrough = ast_true(value);
1195 
1196  ast_channel_unlock(chan);
1197 
1198  return 0;
1199 }
1200 
1201 static int refresh_write_cb(void *obj)
1202 {
1203  struct refresh_data *data = obj;
1204  struct session_refresh_state *state;
1205 
1206  state = session_refresh_state_get_or_alloc(data->session);
1207  if (!state) {
1208  return -1;
1209  }
1210 
1211  ast_sip_session_refresh(data->session, NULL, NULL,
1212  sip_session_response_cb, data->method, 1, state->media_state);
1213 
1214  state->media_state = NULL;
1215  ast_sip_session_remove_datastore(data->session, "pjsip_session_refresh");
1216 
1217  return 0;
1218 }
1219 
1220 int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1221 {
1222  struct ast_sip_channel_pvt *channel;
1223  struct refresh_data rdata = {
1224  .method = AST_SIP_SESSION_REFRESH_METHOD_INVITE,
1225  };
1226 
1227  if (!chan) {
1228  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1229  return -1;
1230  }
1231 
1232  if (ast_channel_state(chan) != AST_STATE_UP) {
1233  ast_log(LOG_WARNING, "'%s' not allowed on unanswered channel '%s'.\n", cmd, ast_channel_name(chan));
1234  return -1;
1235  }
1236 
1237  if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1238  ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1239  return -1;
1240  }
1241 
1242  channel = ast_channel_tech_pvt(chan);
1243  rdata.session = channel->session;
1244 
1245  if (!strcmp(value, "invite")) {
1246  rdata.method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
1247  } else if (!strcmp(value, "update")) {
1248  rdata.method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
1249  }
1250 
1251  return ast_sip_push_task_wait_serializer(channel->session->serializer, refresh_write_cb, &rdata);
1252 }
1253 
1254 struct hangup_data {
1255  struct ast_sip_session *session;
1256  int response_code;
1257 };
1258 
1259 /*!
1260  * \brief Serializer task to hangup channel
1261  */
1262 static int pjsip_hangup(void *obj)
1263 {
1264  struct hangup_data *hdata = obj;
1265  pjsip_tx_data *packet = NULL;
1266 
1267  if ((hdata->session->inv_session->state != PJSIP_INV_STATE_DISCONNECTED) &&
1268  (pjsip_inv_answer(hdata->session->inv_session, hdata->response_code, NULL, NULL, &packet) == PJ_SUCCESS)) {
1269  ast_sip_session_send_response(hdata->session, packet);
1270  }
1271 
1272  return 0;
1273 }
1274 
1275 /*!
1276  * \brief Callback that validates the response code
1277  */
1278 static int response_code_validator(const char *channel_name,
1279  const char *response) {
1280  int response_code;
1281 
1282  int rc = ast_str_to_int(response, &response_code);
1283  if (rc != 0) {
1284  response_code = ast_sip_str2rc(response);
1285  if (response_code < 0) {
1286  ast_log(LOG_WARNING, "%s: Unrecognized response code parameter '%s'."
1287  " Defaulting to 603 DECLINE\n",
1288  channel_name, response);
1289  return PJSIP_SC_DECLINE;
1290  }
1291  }
1292 
1293  if (response_code < 400 || response_code > 699) {
1294  ast_log(LOG_WARNING, "%s: Response code %d is out of range 400 -> 699."
1295  " Defaulting to 603 DECLINE\n",
1296  channel_name, response_code);
1297  return PJSIP_SC_DECLINE;
1298  }
1299  return response_code;
1300 }
1301 
1302 /*!
1303  * \brief Called by pjsip_app_hangup and pjsip_action_hangup
1304  * to actually perform the hangup
1305  */
1306 static void pjsip_app_hangup_handler(struct ast_channel *chan, int response_code)
1307 {
1308  struct ast_sip_channel_pvt *channel;
1309  struct hangup_data hdata = { NULL, -1 };
1310  const char *tag = ast_channel_name(chan);
1311 
1312  hdata.response_code = response_code;
1313 
1314  ast_channel_lock(chan);
1315  if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1316  ast_log(LOG_WARNING, "%s: Not a PJSIP channel\n", tag);
1317  ast_channel_unlock(chan);
1318  return;
1319  }
1320 
1321  channel = ast_channel_tech_pvt(chan);
1322  hdata.session = channel->session;
1323 
1324  if (hdata.session->inv_session->role != PJSIP_ROLE_UAS || (
1325  hdata.session->inv_session->state != PJSIP_INV_STATE_INCOMING &&
1326  hdata.session->inv_session->state != PJSIP_INV_STATE_EARLY)) {
1327  ast_log(LOG_WARNING, "%s: Not an incoming channel or invalid state '%s'\n",
1328  tag, pjsip_inv_state_name(hdata.session->inv_session->state));
1329  ast_channel_unlock(chan);
1330  return;
1331  }
1332 
1333  ast_channel_unlock(chan);
1334 
1336  pjsip_hangup, &hdata) != 0) {
1337  ast_log(LOG_WARNING, "%s: failed to push hangup task to serializer\n", tag);
1338  }
1339 
1340  return;
1341 }
1342 
1343 /*!
1344  * \brief PJSIPHangup Dialplan App
1345  */
1346 int pjsip_app_hangup(struct ast_channel *chan, const char *data)
1347 {
1348  int response_code;
1349  const char *tag = ast_channel_name(chan);
1350 
1351  if (ast_strlen_zero(data)) {
1352  ast_log(LOG_WARNING, "%s: Missing response code parameter\n", tag);
1353  return -1;
1354  }
1355 
1356  response_code = response_code_validator(tag, data);
1357 
1358  pjsip_app_hangup_handler(chan, response_code);
1359 
1360  return -1;
1361 }
1362 
1363 /*!
1364  * \brief PJSIPHangup Manager Action
1365  */
1366 int pjsip_action_hangup(struct mansession *s, const struct message *m)
1367 {
1368  return ast_manager_hangup_helper(s, m,
1370 }
const char * type
Definition: datastore.h:32
structure for secure RTP audio
Definition: sdp_srtp.h:38
enum ast_sip_session_t38state t38state
Main Channel structure associated with a channel.
struct ast_sip_endpoint * endpoint
pj_sockaddr local_addr
Our address that received the request.
Definition: chan_pjsip.h:34
Asterisk main include file. File version handling, generic pbx functions.
Structure which contains media state information (streams, sessions)
PJSIP dialplan functions header file.
A SIP address of record.
Definition: res_pjsip.h:478
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
struct ast_sip_session_media_state * pending_media_state
struct ast_sockaddr direct_media_addr
Direct media address.
int ast_rtp_instance_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode)
Set the DTMF mode that should be used.
Definition: rtp_engine.c:2247
Struct used to push PJSIP_PARSE_URI function arguments to task processor.
int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
Retrieve statistics about an RTP instance.
Definition: rtp_engine.c:2570
int pjsip_acf_moh_passthrough_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
PJSIP_MOH_PASSTHROUGH function read callback.
pjsip_uri * request_uri
Convenient Signal Processing routines.
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
struct ast_sip_session_media_state * media_state
Created proposed media state.
static pj_pool_t * pool
Global memory pool for configuration and timers.
static void session_refresh_state_destroy(void *obj)
Destructor for session refresh information.
Set when the stream has been removed/declined.
Definition: stream.h:78
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
Session refresh state information.
Structure for a data store type.
Definition: datastore.h:31
ast_channel_state
ast_channel states
Definition: channelstate.h:35
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
Definition of a media format.
Definition: format.c:43
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
size_t ast_format_cap_count(const struct ast_format_cap *cap)
Get the number of formats present within the capabilities structure.
Definition: format_cap.c:395
struct ast_format * ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type)
Get the most preferred format for a particular media type.
Definition: format_cap.c:417
static const char * t38state_to_string[T38_MAX_ENUM]
String representations of the T.38 state enum.
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
Structure for a data store object.
Definition: datastore.h:64
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
struct pjsip_inv_session * inv_session
Transport information stored in transport_info datastore.
Definition: chan_pjsip.h:30
void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
Definition: stream.c:365
void ast_free_ptr(void *ptr)
free() wrapper
Definition: main/astmm.c:1739
Socket address structure.
Definition: netsock2.h:97
A structure describing a SIP session.
int ast_manager_hangup_helper(struct mansession *s, const struct message *m, manager_hangup_handler_t handler, manager_hangup_cause_validator_t cause_validator)
A manager helper function that hangs up a channel using a supplied channel type specific hangup funct...
Definition: manager.c:4762
int pjsip_action_hangup(struct mansession *s, const struct message *m)
PJSIPHangup Manager Action.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Media Stream API.
Media Format API.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
struct ast_sip_session_media_state * active_media_state
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
Parse an "allow" or "deny" list and modify a format capabilities structure accordingly.
Definition: format_cap.c:320
int pjsip_acf_moh_passthrough_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_MOH_PASSTHROUGH function write callback.
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:980
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
struct ast_dsp * dsp
int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_DTMF_MODE function write callback.
int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
CHANNEL function read callback.
int ast_dsp_get_features(struct ast_dsp *dsp)
Get features.
Definition: dsp.c:1777
struct ast_stream * ast_stream_topology_get_first_stream_by_type(const struct ast_stream_topology *topology, enum ast_media_type type)
Gets the first active stream of a specific type from the topology.
Definition: stream.c:964
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
PJSIP_DIAL_CONTACTS function read callback.
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:2179
static char * func_args(char *function)
return a pointer to the arguments of the function, and terminates the function name with '\0' ...
Access Control of various sorts.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1785
Conversion utility functions.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
struct ast_channel * channel
#define ast_debug(level,...)
Log a DEBUG message.
struct ast_sdp_srtp * srtp
Holds SRTP information.
const struct ast_format_cap * ast_stream_get_formats(const struct ast_stream *stream)
Get the current negotiated formats of a stream.
Definition: stream.c:330
An entity with which Asterisk communicates.
Definition: res_pjsip.h:949
char * ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_rtp_instance_stat_field field, char *buf, size_t size)
Retrieve quality statistics about an RTP instance.
Definition: rtp_engine.c:2588
int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_MEDIA_OFFER function write callback.
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:628
Core PBX routines and definitions.
void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Remove all formats matching a specific format type.
Definition: format_cap.c:523
struct ast_taskprocessor * serializer
int ast_str_to_int(const char *str, int *res)
Convert the given string to a signed integer.
Definition: conversions.c:44
static void pjsip_app_hangup_handler(struct ast_channel *chan, int response_code)
Called by pjsip_app_hangup and pjsip_action_hangup to actually perform the hangup.
int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
PJSIP_PARSE_URI function read callback.
pj_sockaddr remote_addr
The address that sent the request.
Definition: chan_pjsip.h:32
int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_SEND_SESSION_REFRESH function write callback.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: utils.c:2199
Support for dynamic strings.
Definition: strings.h:623
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
enum ast_sip_dtmf_mode dtmf
Contact associated with an address of record.
Definition: res_pjsip.h:392
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
unsigned int remotely_held
Stream is on hold by remote side.
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1768
PJSIP Channel Driver shared data structures.
static int pjsip_hangup(void *obj)
Serializer task to hangup channel.
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
Definition: utils.c:781
static struct session_refresh_state * session_refresh_state_get_or_alloc(struct ast_sip_session *session)
Helper function which retrieves or allocates a session refresh state information datastore.
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
A structure containing SIP session media information.
void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address)
Get the local address that we are expecting RTP on.
Definition: rtp_engine.c:665
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
PJSIP_DTMF_MODE function read callback.
#define AST_YESNO(x)
return Yes or No depending on the argument.
Definition: strings.h:143
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
const ast_string_field aor
Definition: res_pjsip.h:414
ast_rtp_instance_stat_field
Definition: rtp_engine.h:171
struct ast_stream_topology * topology
Definition: res_pjsip.h:909
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
struct ast_stream_topology * topology
The media stream topology.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#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
struct ast_rtp_instance * rtp
RTP instance itself.
int ast_stream_set_metadata(struct ast_stream *stream, const char *m_key, const char *value)
Set a stream metadata value.
Definition: stream.c:460
enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *instance)
Get the DTMF mode of an RTP instance.
Definition: rtp_engine.c:2261
int pjsip_app_hangup(struct ast_channel *chan, const char *data)
PJSIPHangup Dialplan App.
void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
Set the value of an RTP instance property.
Definition: rtp_engine.c:727
ast_media_type
Types of media.
Definition: codec.h:30
Struct used to push function arguments to task processor.
Generic container type.
int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type)
Append the formats of provided type in src to dst.
Definition: format_cap.c:269
struct ast_format * ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
Get the format at a specific index.
Definition: format_cap.c:400
const ast_string_field uri
Definition: res_pjsip.h:414
struct ast_sip_contact * contact
static int response_code_validator(const char *channel_name, const char *response)
Callback that validates the response code.
Asterisk module definitions.
struct ast_sip_aor * aor
int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
PJSIP_MEDIA_OFFER function read callback.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_rtp_instance_get_remote_address(instance, address)
Get the address of the remote endpoint that we are sending RTP to.
Definition: rtp_engine.h:1245
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
static const struct ast_datastore_info session_refresh_datastore
Datastore for attaching session refresh state information.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
unsigned int moh_passthrough
#define AST_APP_ARG(name)
Define an application argument.