Asterisk - The Open Source Telephony Project GIT-master-f36a736
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"
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"
50#include "include/chan_pjsip.h"
52
53/*!
54 * \brief String representations of the T.38 state enum
55 */
56static 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 */
67static 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);
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")) {
108 } else if (!strcmp(type, "dest")) {
111 } else if (!strcmp(type, "direct")) {
113 } else if (!strcmp(type, "secure")) {
114 if (media->srtp) {
115 struct ast_sdp_srtp *srtp = media->srtp;
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 */
134static 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
263static 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 */
287static 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")) {
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 */
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 */
389static 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
443int 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);
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
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;
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
510int 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
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, ",")))) {
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;
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
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 */
590static void session_refresh_state_destroy(void *obj)
591{
592 struct session_refresh_state *state = obj;
593
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;
623 if (!state->media_state) {
624 ast_sip_session_remove_datastore(session, "pjsip_session_refresh");
625 return NULL;
626 }
627 state->media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);
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 */
648static 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
724int 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);
732 );
733
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;
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
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 */
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) {
802 session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.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
864 const char *value;
865};
866
867static 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) {
876
877 /* As we've already answered we need to store our media state until we are ready to send it */
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 */
901 if (!stream) {
902 return 0;
903 }
904
906 if (!caps) {
907 return -1;
908 }
909
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
921int 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")) {
939 } else if (!strcmp(data, "video")) {
941 } else {
942 /* Ensure that the buffer is empty */
943 buf[0] = '\0';
944 }
945
946 return 0;
947}
948
949int 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")) {
971 } else if (!strcmp(data, "video")) {
973 }
974
976}
977
978int 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
1006int 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
1037};
1038
1039static 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
1049 if (!fmt) {
1050 /* No format? That's weird. */
1051 return 0;
1052 }
1053 ast_channel_set_writeformat(session->channel, fmt);
1055 ast_channel_set_readformat(session->channel, fmt);
1057 ao2_ref(fmt, -1);
1058
1059 return 0;
1060}
1061
1062static 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
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));
1074 }
1075
1076 return 0;
1077}
1078
1079int 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 = {
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
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
1175}
1176
1177int 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);
1195
1196 ast_channel_unlock(chan);
1197
1198 return 0;
1199}
1200
1201static int refresh_write_cb(void *obj)
1202{
1203 struct refresh_data *data = obj;
1205
1207 if (!state) {
1208 return -1;
1209 }
1210
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
1220int 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 = {
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")) {
1247 } else if (!strcmp(value, "update")) {
1249 }
1250
1252}
1253
1254struct hangup_data {
1257};
1258
1259/*!
1260 * \brief Serializer task to hangup channel
1261 */
1262static 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 */
1278static 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 */
1307{
1308 struct ast_sip_channel_pvt *channel;
1309 struct hangup_data hdata = { NULL, -1 };
1310 const char *tag = ast_channel_name(chan);
1311
1313
1315 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1316 ast_log(LOG_WARNING, "%s: Not a PJSIP channel\n", tag);
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));
1330 return;
1331 }
1332
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 */
1346int 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
1357
1359
1360 return -1;
1361}
1362
1363/*!
1364 * \brief PJSIPHangup Manager Action
1365 */
1366int pjsip_action_hangup(struct mansession *s, const struct message *m)
1367{
1368 return ast_manager_hangup_helper(s, m,
1370}
Access Control of various sorts.
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static int tmp()
Definition: bt_open.c:389
enum cc_state state
Definition: ccss.c:393
static const char type[]
Definition: chan_ooh323.c:109
PJSIP Channel Driver shared data structures.
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2968
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2969
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
ast_media_type
Types of media.
Definition: codec.h:30
@ AST_MEDIA_TYPE_AUDIO
Definition: codec.h:32
@ AST_MEDIA_TYPE_UNKNOWN
Definition: codec.h:31
@ AST_MEDIA_TYPE_VIDEO
Definition: codec.h:33
Conversion utility functions.
int ast_str_to_int(const char *str, int *res)
Convert the given string to a signed integer.
Definition: conversions.c:44
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.
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.
int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_MEDIA_OFFER function write callback.
static int read_pjsip(void *data)
static int pjsip_hangup(void *obj)
Serializer task to hangup channel.
static int response_code_validator(const char *channel_name, const char *response)
Callback that validates the response code.
static int refresh_write_cb(void *obj)
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_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_SEND_SESSION_REFRESH function write callback.
static int media_offer_read_av(struct ast_sip_session *session, char *buf, size_t len, enum ast_media_type media_type)
static int media_offer_write_av(void *obj)
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.
static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
static void session_refresh_state_destroy(void *obj)
Destructor for session refresh information.
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.
static int print_escaped_uri(struct ast_channel *chan, const char *type, pjsip_uri_context_e context, const void *uri, char *buf, size_t size)
int pjsip_app_hangup(struct ast_channel *chan, const char *data)
PJSIPHangup Dialplan App.
static const char * t38state_to_string[T38_MAX_ENUM]
String representations of the T.38 state enum.
int pjsip_acf_moh_passthrough_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_MOH_PASSTHROUGH function write callback.
static int dtmf_mode_refresh_cb(void *obj)
int pjsip_action_hangup(struct mansession *s, const struct message *m)
PJSIPHangup Manager Action.
int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
CHANNEL function read callback.
static int channel_read_pjsip(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
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.
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.
static const struct ast_datastore_info session_refresh_datastore
Datastore for attaching session refresh state information.
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.
static int channel_read_rtcp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
static int parse_uri_cb(void *data)
PJSIP dialplan functions header file.
Convenient Signal Processing routines.
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
#define DSP_FEATURE_DIGIT_DETECT
Definition: dsp.h:28
int ast_dsp_get_features(struct ast_dsp *dsp)
Get features.
Definition: dsp.c:1777
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1768
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
long int flag
Definition: f2c.h:83
Media Format API.
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
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
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
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
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
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
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
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
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
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
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:3342
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
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * strsep(char **str, const char *delims)
#define AST_LOG_WARNING
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
Asterisk module definitions.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
Core PBX routines and definitions.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static char * func_args(char *function)
return a pointer to the arguments of the function, and terminates the function name with '\0'
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
Definition: location.c:147
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf, char *buf, size_t buf_len)
Convert the DTMF mode enum value into a string.
Definition: res_pjsip.c:2504
int ast_sip_str2rc(const char *name)
Convert name to SIP response code.
Definition: res_pjsip.c:3714
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
@ AST_SIP_CONTACT_FILTER_REACHABLE
Return only reachable or unknown contacts.
Definition: res_pjsip.h:1305
@ AST_SIP_DTMF_NONE
Definition: res_pjsip.h:542
@ AST_SIP_DTMF_AUTO_INFO
Definition: res_pjsip.h:553
@ AST_SIP_DTMF_AUTO
Definition: res_pjsip.h:551
@ AST_SIP_DTMF_INBAND
Definition: res_pjsip.h:547
@ AST_SIP_DTMF_INFO
Definition: res_pjsip.h:549
@ AST_SIP_DTMF_RFC_4733
Definition: res_pjsip.h:545
int ast_sip_str_to_dtmf(const char *dtmf_mode)
Convert the DTMF mode name into an enum.
Definition: res_pjsip.c:2533
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
struct ao2_container * ast_sip_location_retrieve_aor_contacts_filtered(const struct ast_sip_aor *aor, unsigned int flags)
Retrieve all contacts currently available for an AOR and filter based on flags.
Definition: location.c:252
ast_sip_session_refresh_method
Definition: res_pjsip.h:620
@ AST_SIP_SESSION_REFRESH_METHOD_UPDATE
Definition: res_pjsip.h:624
@ AST_SIP_SESSION_REFRESH_METHOD_INVITE
Definition: res_pjsip.h:622
int ast_sip_session_regenerate_answer(struct ast_sip_session *session, ast_sip_session_sdp_creation_cb on_sdp_creation)
Regenerate SDP Answer.
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
@ T38_PEER_REINVITE
@ T38_LOCAL_REINVITE
@ T38_MAX_ENUM
@ T38_ENABLED
@ T38_REJECTED
@ T38_DISABLED
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc(void)
Allocate a session media state structure.
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
void ast_sip_session_remove_datastore(struct ast_sip_session *session, const char *name)
Remove a session datastore from the session.
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
struct ast_datastore * ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
int ast_sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *media_state)
Send a reinvite or UPDATE on a session.
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
#define NULL
Definition: resample.c:96
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:2313
@ AST_RTP_DTMF_MODE_RFC2833
Definition: rtp_engine.h:155
@ AST_RTP_DTMF_MODE_INBAND
Definition: rtp_engine.h:157
@ AST_RTP_DTMF_MODE_NONE
Definition: rtp_engine.h:153
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:2299
ast_rtp_instance_stat_field
Definition: rtp_engine.h:171
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS
Definition: rtp_engine.h:177
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT
Definition: rtp_engine.h:179
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY
Definition: rtp_engine.h:173
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER
Definition: rtp_engine.h:175
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES
Definition: rtp_engine.h:181
@ AST_RTP_INSTANCE_STAT_ALL
Definition: rtp_engine.h:187
#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:1250
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:2640
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
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
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:2622
@ AST_RTP_PROPERTY_DTMF
Definition: rtp_engine.h:120
#define AST_SRTP_CRYPTO_OFFER_OK
Definition: sdp_srtp.h:45
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
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
Media Stream API.
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
@ AST_STREAM_STATE_REMOVED
Set when the stream has been removed/declined.
Definition: stream.h:78
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:791
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:768
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
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
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
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:670
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:967
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
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
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
#define AST_YESNO(x)
return Yes or No depending on the argument.
Definition: strings.h:143
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Main Channel structure associated with a channel.
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Definition of a media format.
Definition: format.c:43
unsigned int remote_ssrc
Definition: rtp_engine.h:454
unsigned int rxcount
Definition: rtp_engine.h:400
unsigned int local_ssrc
Definition: rtp_engine.h:452
unsigned int rxploss
Definition: rtp_engine.h:424
unsigned int txcount
Definition: rtp_engine.h:398
unsigned int txploss
Definition: rtp_engine.h:422
structure for secure RTP audio
Definition: sdp_srtp.h:38
A SIP address of record.
Definition: res_pjsip.h:475
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
Contact associated with an address of record.
Definition: res_pjsip.h:389
const ast_string_field uri
Definition: res_pjsip.h:411
const ast_string_field aor
Definition: res_pjsip.h:411
struct ast_stream_topology * topology
Definition: res_pjsip.h:918
An entity with which Asterisk communicates.
Definition: res_pjsip.h:958
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:991
Structure which contains media state information (streams, sessions)
struct ast_stream_topology * topology
The media stream topology.
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
A structure containing SIP session media information.
struct ast_sdp_srtp * srtp
Holds SRTP information.
unsigned int remotely_held
Stream is on hold by remote side.
struct ast_rtp_instance * rtp
RTP instance itself.
struct ast_sockaddr direct_media_addr
Direct media address.
A structure describing a SIP session.
pjsip_uri * request_uri
struct ast_sip_endpoint * endpoint
enum ast_sip_session_t38state t38state
struct ast_channel * channel
unsigned int moh_passthrough
struct ast_sip_session_media_state * active_media_state
struct ast_sip_session_media_state * pending_media_state
struct ast_dsp * dsp
struct pjsip_inv_session * inv_session
enum ast_sip_dtmf_mode dtmf
struct ast_taskprocessor * serializer
Socket address structure.
Definition: netsock2.h:97
Support for dynamic strings.
Definition: strings.h:623
struct ast_sip_session * session
struct ast_channel * chan
Definition: chan_pjsip.c:2487
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:326
enum ast_media_type media_type
struct ast_sip_session * session
Struct used to push PJSIP_PARSE_URI function arguments to task processor.
Struct used to push function arguments to task processor.
struct ast_sip_session * session
struct ast_sip_session * session
enum ast_sip_session_refresh_method method
Session refresh state information.
struct ast_sip_session_media_state * media_state
Created proposed media state.
Transport information stored in transport_info datastore.
Definition: chan_pjsip.h:30
pj_sockaddr local_addr
Our address that received the request.
Definition: chan_pjsip.h:34
pj_sockaddr remote_addr
The address that sent the request.
Definition: chan_pjsip.h:32
int value
Definition: syslog.c:37
const char * args
#define ast_test_flag(p, flag)
Definition: utils.h:63
#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
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
Definition: utils.c:781