Asterisk - The Open Source Telephony Project GIT-master-80b953f
Loading...
Searching...
No Matches
cel.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2007 - 2009, 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 * \brief Channel Event Logging API
21 *
22 * \author Steve Murphy <murf@digium.com>
23 * \author Russell Bryant <russell@digium.com>
24 */
25
26/*! \li \ref cel.c uses the configuration file \ref cel.conf
27 * \addtogroup configuration_file Configuration Files
28 */
29
30/*!
31 * \page cel.conf cel.conf
32 * \verbinclude cel.conf.sample
33 */
34
35/*** MODULEINFO
36 <support_level>core</support_level>
37 ***/
38
39#include "asterisk.h"
40
41#include "asterisk/module.h"
42
43#include "asterisk/channel.h"
44#include "asterisk/pbx.h"
45#include "asterisk/cel.h"
46#include "asterisk/logger.h"
48#include "asterisk/utils.h"
49#include "asterisk/config.h"
51#include "asterisk/cli.h"
52#include "asterisk/astobj2.h"
56#include "asterisk/bridge.h"
57#include "asterisk/parking.h"
58#include "asterisk/pickup.h"
59#include "asterisk/core_local.h"
61
62/*** DOCUMENTATION
63 <configInfo name="cel" language="en_US">
64 <configFile name="cel.conf">
65 <configObject name="general">
66 <since>
67 <version>12.0.0</version>
68 </since>
69 <synopsis>Options that apply globally to Channel Event Logging (CEL)</synopsis>
70 <configOption name="enable">
71 <since>
72 <version>12.0.0</version>
73 </since>
74 <synopsis>Determines whether CEL is enabled</synopsis>
75 </configOption>
76 <configOption name="dateformat">
77 <since>
78 <version>12.0.0</version>
79 </since>
80 <synopsis>The format to be used for dates when logging</synopsis>
81 </configOption>
82 <configOption name="apps">
83 <since>
84 <version>12.0.0</version>
85 </since>
86 <synopsis>List of apps for CEL to track</synopsis>
87 <description><para>A case-insensitive, comma-separated list of applications
88 to track when one or both of APP_START and APP_END events are flagged for
89 tracking</para></description>
90 </configOption>
91 <configOption name="events">
92 <since>
93 <version>12.0.0</version>
94 </since>
95 <synopsis>List of events for CEL to track</synopsis>
96 <description><para>A case-sensitive, comma-separated list of event names
97 to track. These event names do not include the leading <literal>AST_CEL</literal>.
98 </para>
99 <enumlist>
100 <enum name="ALL">
101 <para>Special value which tracks all events.</para>
102 </enum>
103 <enum name="CHAN_START"/>
104 <enum name="CHAN_END"/>
105 <enum name="ANSWER"/>
106 <enum name="HANGUP"/>
107 <enum name="APP_START"/>
108 <enum name="APP_END"/>
109 <enum name="PARK_START"/>
110 <enum name="PARK_END"/>
111 <enum name="USER_DEFINED"/>
112 <enum name="BRIDGE_ENTER"/>
113 <enum name="BRIDGE_EXIT"/>
114 <enum name="BLINDTRANSFER"/>
115 <enum name="ATTENDEDTRANSFER"/>
116 <enum name="PICKUP"/>
117 <enum name="FORWARD"/>
118 <enum name="LINKEDID_END"/>
119 <enum name="LOCAL_OPTIMIZE"/>
120 <enum name="LOCAL_OPTIMIZE_BEGIN"/>
121 <enum name="STREAM_BEGIN"/>
122 <enum name="STREAM_END"/>
123 <enum name="DTMF"/>
124 </enumlist>
125 </description>
126 </configOption>
127 </configObject>
128 </configFile>
129 </configInfo>
130 ***/
131
132/*! Message router for state that CEL needs to know about */
134
135/*! Topic for CEL-specific messages */
136static struct stasis_topic *cel_topic;
137
138/*! Aggregation topic for all topics CEL needs to know about */
140
141/*! Subscription for forwarding the channel caching topic */
143
144/*! Subscription for forwarding the channel caching topic */
146
147/*! Subscription for forwarding the parking topic */
149
150/*! Subscription for forwarding the CEL-specific topic */
152
155
156/*! Container for CEL backend information */
157static AO2_GLOBAL_OBJ_STATIC(cel_backends);
158
159/*! The number of buckets into which backend names will be hashed */
160#define BACKEND_BUCKETS 13
161
162/*! Container for dial end multichannel blobs for holding on to dial statuses */
163static AO2_GLOBAL_OBJ_STATIC(cel_dialstatus_store);
164
165/*!
166 * \brief Maximum possible CEL event IDs
167 * \note This limit is currently imposed by the eventset definition
168 */
169#define CEL_MAX_EVENT_IDS 64
170
171/*!
172 * \brief Number of buckets for the appset container
173 */
174#define NUM_APP_BUCKETS 97
175
176/*!
177 * \brief Number of buckets for the dialstatus container
178 */
179#define NUM_DIALSTATUS_BUCKETS 251
180
182 /*! Number of channels with this linkedid. */
183 unsigned int count;
184 /*! Linkedid stored at end of struct. */
185 char id[0];
186};
187
188/*! Container of channel references to a linkedid for CEL purposes. */
189static AO2_GLOBAL_OBJ_STATIC(cel_linkedids);
190
192 /*! Uniqueid of the channel */
194 /*! The dial status */
195 char dialstatus[0];
196};
197
198/*! \brief Destructor for cel_config */
199static void cel_general_config_dtor(void *obj)
200{
201 struct ast_cel_general_config *cfg = obj;
203 ao2_cleanup(cfg->apps);
204 cfg->apps = NULL;
205}
206
208{
210
211 if (!(cfg = ao2_alloc(sizeof(*cfg), cel_general_config_dtor))) {
212 return NULL;
213 }
214
215 if (ast_string_field_init(cfg, 64)) {
216 return NULL;
217 }
218
219 if (!(cfg->apps = ast_str_container_alloc(NUM_APP_BUCKETS))) {
220 return NULL;
221 }
222
223 ao2_ref(cfg, +1);
224 return cfg;
225}
226
227/*! \brief A container that holds all config-related information */
231
232
233static AO2_GLOBAL_OBJ_STATIC(cel_configs);
234
235/*! \brief Destructor for cel_config */
236static void cel_config_dtor(void *obj)
237{
238 struct cel_config *cfg = obj;
239 ao2_cleanup(cfg->general);
240 cfg->general = NULL;
241}
242
243static void *cel_config_alloc(void)
244{
245 RAII_VAR(struct cel_config *, cfg, NULL, ao2_cleanup);
246
247 if (!(cfg = ao2_alloc(sizeof(*cfg), cel_config_dtor))) {
248 return NULL;
249 }
250
251 if (!(cfg->general = ast_cel_general_config_alloc())) {
252 return NULL;
253 }
254
255 ao2_ref(cfg, +1);
256 return cfg;
257}
258
259/*! \brief An aco_type structure to link the "general" category to the ast_cel_general_config type */
260static struct aco_type general_option = {
261 .type = ACO_GLOBAL,
262 .name = "general",
263 .item_offset = offsetof(struct cel_config, general),
264 .category_match = ACO_WHITELIST_EXACT,
265 .category = "general",
266};
267
268/*! Config sections used by existing modules. Do not add to this list. */
269static const char *ignore_categories[] = {
270 "manager",
271 "radius",
272 NULL,
273};
274
275static struct aco_type ignore_option = {
276 .type = ACO_IGNORE,
277 .name = "modules",
278 .category = (const char*)ignore_categories,
280};
281
282/*! \brief The config file to be processed for the module. */
283static struct aco_file cel_conf = {
284 .filename = "cel.conf", /*!< The name of the config file */
285 .types = ACO_TYPES(&general_option, &ignore_option), /*!< The mapping object types to be processed */
286};
287
288static int cel_pre_apply_config(void);
289
290CONFIG_INFO_CORE("cel", cel_cfg_info, cel_configs, cel_config_alloc,
291 .files = ACO_FILES(&cel_conf),
292 .pre_apply_config = cel_pre_apply_config,
293);
294
295static int cel_pre_apply_config(void)
296{
297 struct cel_config *cfg = aco_pending_config(&cel_cfg_info);
298
299 if (!cfg->general) {
300 return -1;
301 }
302
303 if (!ao2_container_count(cfg->general->apps)) {
304 return 0;
305 }
306
307 if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_START)) {
308 return 0;
309 }
310
311 if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_END)) {
312 return 0;
313 }
314
315 ast_log(LOG_ERROR, "Applications are listed to be tracked, but APP events are not tracked\n");
316 return -1;
317}
318
320
321/*!
322 * \brief Map of ast_cel_event_type to strings
323 */
324static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
325 [AST_CEL_ALL] = "ALL",
326 [AST_CEL_CHANNEL_START] = "CHAN_START",
327 [AST_CEL_CHANNEL_END] = "CHAN_END",
328 [AST_CEL_ANSWER] = "ANSWER",
329 [AST_CEL_HANGUP] = "HANGUP",
330 [AST_CEL_APP_START] = "APP_START",
331 [AST_CEL_APP_END] = "APP_END",
332 [AST_CEL_PARK_START] = "PARK_START",
333 [AST_CEL_PARK_END] = "PARK_END",
334 [AST_CEL_USER_DEFINED] = "USER_DEFINED",
335 [AST_CEL_BRIDGE_ENTER] = "BRIDGE_ENTER",
336 [AST_CEL_BRIDGE_EXIT] = "BRIDGE_EXIT",
337 [AST_CEL_BLINDTRANSFER] = "BLINDTRANSFER",
338 [AST_CEL_ATTENDEDTRANSFER] = "ATTENDEDTRANSFER",
339 [AST_CEL_PICKUP] = "PICKUP",
340 [AST_CEL_FORWARD] = "FORWARD",
341 [AST_CEL_LINKEDID_END] = "LINKEDID_END",
342 [AST_CEL_LOCAL_OPTIMIZE] = "LOCAL_OPTIMIZE",
343 [AST_CEL_LOCAL_OPTIMIZE_BEGIN] = "LOCAL_OPTIMIZE_BEGIN",
344 [AST_CEL_STREAM_BEGIN] = "STREAM_BEGIN",
345 [AST_CEL_STREAM_END] = "STREAM_END",
346 [AST_CEL_DTMF] = "DTMF",
347};
348
350 ast_cel_backend_cb callback; /*!< Callback for this backend */
351 char name[0]; /*!< Name of this backend */
352};
353
354/*! \brief Hashing function for cel_backend */
356
357/*! \brief Comparator function for cel_backend */
359
360/*! \brief Hashing function for dialstatus container */
362
363/*! \brief Comparator function for dialstatus container */
365
366unsigned int ast_cel_check_enabled(void)
367{
368 unsigned int enabled;
369 struct cel_config *cfg = ao2_global_obj_ref(cel_configs);
370
371 enabled = (!cfg || !cfg->general) ? 0 : cfg->general->enable;
372 ao2_cleanup(cfg);
373 return enabled;
374}
375
376static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
377{
378 unsigned int i;
379 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
381 struct ao2_iterator iter;
382 char *app;
383
384 switch (cmd) {
385 case CLI_INIT:
386 e->command = "cel show status";
387 e->usage =
388 "Usage: cel show status\n"
389 " Displays the Channel Event Logging system status.\n";
390 return NULL;
391 case CLI_GENERATE:
392 return NULL;
393 case CLI_HANDLER:
394 break;
395 }
396
397 if (a->argc > 3) {
398 return CLI_SHOWUSAGE;
399 }
400
401 ast_cli(a->fd, "CEL Logging: %s\n", ast_cel_check_enabled() ? "Enabled" : "Disabled");
402
403 if (!cfg || !cfg->general || !cfg->general->enable) {
404 return CLI_SUCCESS;
405 }
406
407 for (i = 0; i < (sizeof(cfg->general->events) * 8); i++) {
408 const char *name;
409
410 if (!(cfg->general->events & ((int64_t) 1 << i))) {
411 continue;
412 }
413
415 if (strcasecmp(name, "Unknown")) {
416 ast_cli(a->fd, "CEL Tracking Event: %s\n", name);
417 }
418 }
419
420 iter = ao2_iterator_init(cfg->general->apps, 0);
421 for (; (app = ao2_iterator_next(&iter)); ao2_ref(app, -1)) {
422 ast_cli(a->fd, "CEL Tracking Application: %s\n", app);
423 }
425
426 if (backends) {
427 struct cel_backend *backend;
428
429 iter = ao2_iterator_init(backends, 0);
430 for (; (backend = ao2_iterator_next(&iter)); ao2_ref(backend, -1)) {
431 ast_cli(a->fd, "CEL Event Subscriber: %s\n", backend->name);
432 }
434 }
435
436 return CLI_SUCCESS;
437}
438
439static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CEL status");
440
442{
443 unsigned int i;
444
445 for (i = 0; i < ARRAY_LEN(cel_event_types); i++) {
446 if (cel_event_types[i] && !strcasecmp(name, cel_event_types[i])) {
447 return i;
448 }
449 }
450
451 ast_log(LOG_ERROR, "Unknown event name '%s'\n", name);
453}
454
456{
457 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
458
459 if (!cfg || !cfg->general) {
460 return 0;
461 }
462
463 return (cfg->general->events & ((int64_t) 1 << et)) ? 1 : 0;
464}
465
466static int events_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
467{
468 struct ast_cel_general_config *cfg = obj;
469 char *events = ast_strdupa(var->value);
470 char *cur_event;
471
472 while ((cur_event = strsep(&events, ","))) {
473 enum ast_cel_event_type event_type;
474
475 cur_event = ast_strip(cur_event);
476 if (ast_strlen_zero(cur_event)) {
477 continue;
478 }
479
480 event_type = ast_cel_str_to_event_type(cur_event);
481
482 if (event_type == AST_CEL_ALL) {
483 /* All events */
484 cfg->events = (int64_t) -1;
485 } else if (event_type == AST_CEL_INVALID_VALUE) {
486 return -1;
487 } else {
488 cfg->events |= ((int64_t) 1 << event_type);
489 }
490 }
491
492 return 0;
493}
494
495static int apps_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
496{
497 struct ast_cel_general_config *cfg = obj;
498 char *apps = ast_strdupa(var->value);
499 char *cur_app;
500
501 while ((cur_app = strsep(&apps, ","))) {
502 cur_app = ast_strip(cur_app);
503 if (ast_strlen_zero(cur_app)) {
504 continue;
505 }
506
507 cur_app = ast_str_to_lower(cur_app);
508 ast_str_container_add(cfg->apps, cur_app);
509 }
510
511 return 0;
512}
513
515{
516 return S_OR(cel_event_types[type], "Unknown");
517}
518
519static int cel_track_app(const char *const_app)
520{
521 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
522 RAII_VAR(char *, app, NULL, ao2_cleanup);
523 char *app_lower;
524
525 if (!cfg || !cfg->general) {
526 return 0;
527 }
528
529 app_lower = ast_str_to_lower(ast_strdupa(const_app));
530 app = ao2_find(cfg->general->apps, app_lower, OBJ_SEARCH_KEY);
531 if (!app) {
532 return 0;
533 }
534
535 return 1;
536}
537
538static int cel_linkedid_ref(const char *linkedid);
539
541 enum ast_cel_event_type event_type, const char *userdefevname,
542 struct ast_json *extra, const char *peer)
543{
544 struct timeval eventtime = ast_tvnow();
545
546 return ast_cel_create_event_with_time(snapshot, event_type, &eventtime,
547 userdefevname, extra, peer);
548}
549
551 enum ast_cel_event_type event_type, const struct timeval *event_time,
552 const char *userdefevname, struct ast_json *extra, const char *peer)
553{
554 RAII_VAR(char *, extra_txt, NULL, ast_json_free);
555 if (extra) {
556 extra_txt = ast_json_dump_string(extra);
557 }
583}
584
585static int cel_backend_send_cb(void *obj, void *arg, int flags)
586{
587 struct cel_backend *backend = obj;
588
589 backend->callback(arg);
590 return 0;
591}
592
593static int cel_report_event(struct ast_channel_snapshot *snapshot,
594 enum ast_cel_event_type event_type, const struct timeval *event_time,
595 const char *userdefevname, struct ast_json *extra,
596 const char *peer_str)
597{
598 struct ast_event *ev;
599 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
601
602 if (!cfg || !cfg->general || !cfg->general->enable || !backends) {
603 return 0;
604 }
605
606 /* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
607 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
608 if (event_type == AST_CEL_CHANNEL_START
610 if (cel_linkedid_ref(snapshot->peer->linkedid)) {
611 return -1;
612 }
613 }
614
615 if (!ast_cel_track_event(event_type)) {
616 return 0;
617 }
618
619 if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
620 && !cel_track_app(snapshot->dialplan->appl)) {
621 return 0;
622 }
623
624 ev = ast_cel_create_event_with_time(snapshot, event_type, event_time, userdefevname, extra, peer_str);
625 if (!ev) {
626 return -1;
627 }
628
629 /* Distribute event to backends */
632
633 return 0;
634}
635
636/* called whenever a channel is destroyed or a linkedid is changed to
637 * potentially emit a CEL_LINKEDID_END event */
638static void check_retire_linkedid(struct ast_channel_snapshot *snapshot, const struct timeval *event_time)
639{
640 RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
641 struct cel_linkedid *lid;
642
643 if (!linkedids || ast_strlen_zero(snapshot->peer->linkedid)) {
644 /* The CEL module is shutdown. Abort. */
645 return;
646 }
647
648 ao2_lock(linkedids);
649
650 lid = ao2_find(linkedids, (void *) snapshot->peer->linkedid, OBJ_SEARCH_KEY);
651 if (!lid) {
652 ao2_unlock(linkedids);
653
654 /*
655 * The user may have done a reload to start tracking linkedids
656 * when a call was already in progress. This is an unusual kind
657 * of change to make after starting Asterisk.
658 */
659 ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n",
660 snapshot->peer->linkedid);
661 return;
662 }
663
664 if (!--lid->count) {
665 /* No channels use this linkedid anymore. */
666 ao2_unlink(linkedids, lid);
667 ao2_unlock(linkedids);
668
669 cel_report_event(snapshot, AST_CEL_LINKEDID_END, event_time, NULL, NULL, NULL);
670 } else {
671 ao2_unlock(linkedids);
672 }
673 ao2_ref(lid, -1);
674}
675
676static int cel_format_eventtime(struct cel_config *cfg, struct timeval eventtime, char *timebuf, size_t len)
677{
678 if (!timebuf || len < 30) {
679 return -1;
680 }
681
683 snprintf(timebuf, len, "%ld.%06ld", (long) eventtime.tv_sec,
684 (long) eventtime.tv_usec);
685 } else {
686 struct ast_tm tm;
687 ast_localtime(&eventtime, &tm, NULL);
688 ast_strftime(timebuf, len, cfg->general->date_format, &tm);
689 }
690
691 return 0;
692}
693
694int ast_cel_format_eventtime(struct timeval eventtime, char *timebuf, size_t len)
695{
696 struct cel_config *cfg = ao2_global_obj_ref(cel_configs);
697 int res = 0;
698
699 if (!cfg) {
700 return -1;
701 }
702
703 res = cel_format_eventtime(cfg, eventtime, timebuf, len);
704 ao2_cleanup(cfg);
705
706 return res;
707}
708
709/* Note that no 'chan_fixup' function is provided for this datastore type,
710 * because the channels that will use it will never be involved in masquerades.
711 */
713 .type = "CEL fabricated channel",
714 .destroy = ast_free_ptr,
715};
716
718{
719 struct varshead *headp;
720 struct ast_var_t *newvariable;
721 const char *mixed_name;
722 char timebuf[30];
723 struct ast_channel *tchan;
724 struct ast_cel_event_record record = {
726 };
727 struct ast_datastore *datastore;
728 char *app_data;
729 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
730
731 if (!cfg || !cfg->general) {
732 return NULL;
733 }
734
735 /* do not call ast_channel_alloc because this is not really a real channel */
736 if (!(tchan = ast_dummy_channel_alloc())) {
737 return NULL;
738 }
739
740 headp = ast_channel_varshead(tchan);
741
742 /* first, get the variables from the event */
743 if (ast_cel_fill_record(event, &record)) {
744 ast_channel_unref(tchan);
745 return NULL;
746 }
747
748 /* next, fill the channel with their data */
749 mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
750 ? record.user_defined_name : record.event_name;
751 if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
752 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
753 }
754
755 cel_format_eventtime(cfg, record.event_time, timebuf, sizeof(timebuf));
756
757 if ((newvariable = ast_var_assign("eventtime", timebuf))) {
758 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
759 }
760
761 if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
762 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
763 }
764 if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
765 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
766 }
767 if ((newvariable = ast_var_assign("eventextra", record.extra))) {
768 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
769 }
770
771 ast_channel_caller(tchan)->id.name.valid = 1;
773 ast_channel_caller(tchan)->id.number.valid = 1;
780
781 ast_channel_exten_set(tchan, record.extension);
782 ast_channel_context_set(tchan, record.context);
783 ast_channel_name_set(tchan, record.channel_name);
785 ast_channel_accountcode_set(tchan, record.account_code);
786 ast_channel_peeraccount_set(tchan, record.peer_account);
787 ast_channel_userfield_set(tchan, record.user_field);
788 ast_channel_tenantid_set(tchan, record.tenant_id);
789
790 if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
791 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
792 }
793
794 ast_channel_amaflags_set(tchan, record.amaflag);
795
796 /* We need to store an 'application name' and 'application
797 * data' on the channel for logging purposes, but the channel
798 * structure only provides a place to store pointers, and it
799 * expects these pointers to be pointing to data that does not
800 * need to be freed. This means that the channel's destructor
801 * does not attempt to free any storage that these pointers
802 * point to. However, we can't provide data in that form directly for
803 * these structure members. In order to ensure that these data
804 * elements have a lifetime that matches the channel's
805 * lifetime, we'll put them in a datastore attached to the
806 * channel, and set's the channel's pointers to point into the
807 * datastore. The datastore will then be automatically destroyed
808 * when the channel is destroyed.
809 */
810
812 ast_channel_unref(tchan);
813 return NULL;
814 }
815
816 if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
817 ast_datastore_free(datastore);
818 ast_channel_unref(tchan);
819 return NULL;
820 }
821
822 ast_channel_appl_set(tchan, strcpy(app_data, record.application_name));
823 ast_channel_data_set(tchan, strcpy(app_data + strlen(record.application_name) + 1,
824 record.application_data));
825
826 datastore->data = app_data;
827 ast_channel_datastore_add(tchan, datastore);
828
829 return tchan;
830}
831
832static int cel_linkedid_ref(const char *linkedid)
833{
834 RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
835 struct cel_linkedid *lid;
836
837 if (ast_strlen_zero(linkedid)) {
838 ast_log(LOG_ERROR, "The linkedid should never be empty\n");
839 return -1;
840 }
841 if (!linkedids) {
842 /* The CEL module is shutdown. Abort. */
843 return -1;
844 }
845
846 ao2_lock(linkedids);
847 lid = ao2_find(linkedids, (void *) linkedid, OBJ_SEARCH_KEY);
848 if (!lid) {
849 /*
850 * Changes to the lid->count member are protected by the
851 * container lock so the lid object does not need its own lock.
852 */
853 lid = ao2_alloc_options(sizeof(*lid) + strlen(linkedid) + 1, NULL,
855 if (!lid) {
856 ao2_unlock(linkedids);
857 return -1;
858 }
859 strcpy(lid->id, linkedid);/* Safe */
860
861 ao2_link(linkedids, lid);
862 }
863 ++lid->count;
864 ao2_unlock(linkedids);
865 ao2_ref(lid, -1);
866
867 return 0;
868}
869
871{
873 ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record. "
874 "Please ensure all modules were compiled for "
875 "this version of Asterisk.\n");
876 return -1;
877 }
878
880
883
885
906
907 return 0;
908}
909
910/*! \brief Typedef for callbacks that get called on channel snapshot updates */
912 struct ast_channel_snapshot *old_snapshot,
913 struct ast_channel_snapshot *new_snapshot,
914 const struct timeval *event_time);
915
916static struct cel_dialstatus *get_dialstatus(const char *uniqueid)
917{
918 struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
920
921 if (dial_statuses) {
923 ao2_ref(dial_statuses, -1);
924 }
925 return dialstatus;
926}
927
928static const char *get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
929{
930 struct ast_json *json = ast_multi_channel_blob_get_json(blob);
931 if (!json) {
932 return NULL;
933 }
934
935 json = ast_json_object_get(json, varname);
936 if (!json) {
937 return NULL;
938 }
939
940 return ast_json_string_get(json);
941}
942
943/*! \brief Handle channel state changes */
945 struct ast_channel_snapshot *old_snapshot,
946 struct ast_channel_snapshot *new_snapshot,
947 const struct timeval *event_time)
948{
949 int is_hungup, was_hungup;
950
951 if (!old_snapshot) {
952 cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, event_time, NULL, NULL, NULL);
953 return;
954 }
955
956 was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
957 is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
958
959 if (!was_hungup && is_hungup) {
960 struct ast_json *extra;
961 struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->base->uniqueid);
962
963 extra = ast_json_pack("{s: i, s: s, s: s}",
964 "hangupcause", new_snapshot->hangup->cause,
965 "hangupsource", new_snapshot->hangup->source,
966 "dialstatus", dialstatus ? dialstatus->dialstatus : "");
967 cel_report_event(new_snapshot, AST_CEL_HANGUP, event_time, NULL, extra, NULL);
968 ast_json_unref(extra);
970
971 cel_report_event(new_snapshot, AST_CEL_CHANNEL_END, event_time, NULL, NULL, NULL);
973 check_retire_linkedid(new_snapshot, event_time);
974 }
975 return;
976 }
977
978 if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
979 cel_report_event(new_snapshot, AST_CEL_ANSWER, event_time, NULL, NULL, NULL);
980 return;
981 }
982}
983
985 struct ast_channel_snapshot *old_snapshot,
986 struct ast_channel_snapshot *new_snapshot,
987 const struct timeval *event_time)
988{
989 if (!old_snapshot) {
990 return;
991 }
992
993 ast_assert(!ast_strlen_zero(new_snapshot->peer->linkedid));
994 ast_assert(!ast_strlen_zero(old_snapshot->peer->linkedid));
995
997 && strcmp(old_snapshot->peer->linkedid, new_snapshot->peer->linkedid)) {
998 cel_linkedid_ref(new_snapshot->peer->linkedid);
999 check_retire_linkedid(old_snapshot, event_time);
1000 }
1001}
1002
1004 struct ast_channel_snapshot *old_snapshot,
1005 struct ast_channel_snapshot *new_snapshot,
1006 const struct timeval *event_time)
1007{
1008 if (old_snapshot && !strcmp(old_snapshot->dialplan->appl, new_snapshot->dialplan->appl)) {
1009 return;
1010 }
1011
1012 /* old snapshot has an application, end it */
1013 if (old_snapshot && !ast_strlen_zero(old_snapshot->dialplan->appl)) {
1014 cel_report_event(old_snapshot, AST_CEL_APP_END, event_time, NULL, NULL, NULL);
1015 }
1016
1017 /* new snapshot has an application, start it */
1018 if (!ast_strlen_zero(new_snapshot->dialplan->appl)) {
1019 cel_report_event(new_snapshot, AST_CEL_APP_START, event_time, NULL, NULL, NULL);
1020 }
1021}
1022
1023/*! \brief Handlers for channel snapshot changes.
1024 * \note Order of the handlers matters. Application changes must come before state
1025 * changes to ensure that hangup notifications occur after application changes.
1026 * Linkedid checking should always come last.
1027 */
1033
1035{
1036 if (!snapshot) {
1037 return 0;
1038 }
1039 return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
1040}
1041
1042static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
1043 struct stasis_message *message)
1044{
1046 size_t i;
1047
1048 if (cel_filter_channel_snapshot(update->old_snapshot) || cel_filter_channel_snapshot(update->new_snapshot)) {
1049 return;
1050 }
1051
1052 for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {
1053 cel_channel_monitors[i](update->old_snapshot, update->new_snapshot, stasis_message_timestamp(message));
1054 }
1055}
1056
1058 struct ast_bridge_snapshot *bridge,
1059 struct ast_channel_snapshot *chan)
1060{
1061 struct ast_str *peer_str = ast_str_create(32);
1062 struct ao2_iterator i;
1063 char *current_chan = NULL;
1064
1065 if (!peer_str) {
1066 return NULL;
1067 }
1068
1069 for (i = ao2_iterator_init(bridge->channels, 0);
1070 (current_chan = ao2_iterator_next(&i));
1071 ao2_cleanup(current_chan)) {
1072 struct ast_channel_snapshot *current_snapshot;
1073
1074 /* Don't add the channel for which this message is being generated */
1075 if (!strcmp(current_chan, chan->base->uniqueid)) {
1076 continue;
1077 }
1078
1079 current_snapshot = ast_channel_snapshot_get_latest(current_chan);
1080 if (!current_snapshot) {
1081 continue;
1082 }
1083
1084 ast_str_append(&peer_str, 0, "%s,", current_snapshot->base->name);
1085 ao2_cleanup(current_snapshot);
1086 }
1088
1089 /* Rip off the trailing comma */
1090 ast_str_truncate(peer_str, -1);
1091
1092 return peer_str;
1093}
1094
1096 void *data, struct stasis_subscription *sub,
1097 struct stasis_message *message)
1098{
1100 struct ast_bridge_snapshot *snapshot = blob->bridge;
1101 struct ast_channel_snapshot *chan_snapshot = blob->channel;
1102 RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1103 RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
1104
1105 if (cel_filter_channel_snapshot(chan_snapshot)) {
1106 return;
1107 }
1108
1109 extra = ast_json_pack("{s: s, s: s}",
1110 "bridge_id", snapshot->uniqueid,
1111 "bridge_technology", snapshot->technology);
1112 if (!extra) {
1113 return;
1114 }
1115
1116 peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
1117 if (!peer_str) {
1118 return;
1119 }
1120
1122 NULL, extra, ast_str_buffer(peer_str));
1123}
1124
1126 void *data, struct stasis_subscription *sub,
1127 struct stasis_message *message)
1128{
1130 struct ast_bridge_snapshot *snapshot = blob->bridge;
1131 struct ast_channel_snapshot *chan_snapshot = blob->channel;
1132 RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1133 RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
1134
1135 if (cel_filter_channel_snapshot(chan_snapshot)) {
1136 return;
1137 }
1138
1139 extra = ast_json_pack("{s: s, s: s}",
1140 "bridge_id", snapshot->uniqueid,
1141 "bridge_technology", snapshot->technology);
1142 if (!extra) {
1143 return;
1144 }
1145
1146 peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
1147 if (!peer_str) {
1148 return;
1149 }
1150
1152 NULL, extra, ast_str_buffer(peer_str));
1153}
1154
1155static void cel_parking_cb(
1156 void *data, struct stasis_subscription *sub,
1157 struct stasis_message *message)
1158{
1159 struct ast_parked_call_payload *parked_payload = stasis_message_data(message);
1160 RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1161 const char *reason = NULL;
1162
1163 switch (parked_payload->event_type) {
1164 case PARKED_CALL:
1165 extra = ast_json_pack("{s: s, s: s}",
1166 "parker_dial_string", parked_payload->parker_dial_string,
1167 "parking_lot", parked_payload->parkinglot);
1168 if (extra) {
1170 NULL, extra, NULL);
1171 }
1172 return;
1174 reason = "ParkedCallTimeOut";
1175 break;
1176 case PARKED_CALL_GIVEUP:
1177 reason = "ParkedCallGiveUp";
1178 break;
1180 reason = "ParkedCallUnparked";
1181 break;
1182 case PARKED_CALL_FAILED:
1183 reason = "ParkedCallFailed";
1184 break;
1185 case PARKED_CALL_SWAP:
1186 reason = "ParkedCallSwap";
1187 break;
1188 }
1189
1190 if (parked_payload->retriever) {
1191 extra = ast_json_pack("{s: s, s: s}",
1192 "reason", reason ?: "",
1193 "retriever", parked_payload->retriever->base->name);
1194 } else {
1195 extra = ast_json_pack("{s: s}", "reason", reason ?: "");
1196 }
1197
1198 if (extra) {
1200 NULL, extra, NULL);
1201 }
1202}
1203
1204static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_channel_snapshot *snapshot)
1205{
1206 struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
1207 const char *dialstatus_string = get_blob_variable(blob, "dialstatus");
1208 struct cel_dialstatus *dialstatus;
1209 size_t dialstatus_string_len;
1210
1211 if (!dial_statuses || ast_strlen_zero(dialstatus_string)) {
1212 ao2_cleanup(dial_statuses);
1213 return;
1214 }
1215
1216 dialstatus = ao2_find(dial_statuses, snapshot->base->uniqueid, OBJ_SEARCH_KEY);
1217 if (dialstatus) {
1218 if (!strcasecmp(dialstatus_string, "ANSWER") && strcasecmp(dialstatus->dialstatus, "ANSWER")) {
1219 /* In the case of an answer after we already have a dial status we give
1220 * priority to the answer since the call was, well, answered. In the case of
1221 * failure dial status results we simply let the first failure be the status.
1222 */
1223 ao2_unlink(dial_statuses, dialstatus);
1224 ao2_ref(dialstatus, -1);
1225 } else {
1226 ao2_ref(dialstatus, -1);
1227 ao2_ref(dial_statuses, -1);
1228 return;
1229 }
1230 }
1231
1232 dialstatus_string_len = strlen(dialstatus_string) + 1;
1233 dialstatus = ao2_alloc_options(sizeof(*dialstatus) + dialstatus_string_len, NULL,
1235 if (!dialstatus) {
1236 ao2_ref(dial_statuses, -1);
1237 return;
1238 }
1239
1240 ast_copy_string(dialstatus->uniqueid, snapshot->base->uniqueid, sizeof(dialstatus->uniqueid));
1241 ast_copy_string(dialstatus->dialstatus, dialstatus_string, dialstatus_string_len);
1242
1243 ao2_link(dial_statuses, dialstatus);
1244 ao2_ref(dialstatus, -1);
1245 ao2_ref(dial_statuses, -1);
1246}
1247
1249{
1250 const char *dialstatus = get_blob_variable(blob, "dialstatus");
1251 int res = 0;
1252
1254 res = 0;
1255 } else if (!strcasecmp(dialstatus, "CHANUNAVAIL")) {
1256 res = 1;
1257 } else if (!strcasecmp(dialstatus, "CONGESTION")) {
1258 res = 1;
1259 } else if (!strcasecmp(dialstatus, "NOANSWER")) {
1260 res = 1;
1261 } else if (!strcasecmp(dialstatus, "BUSY")) {
1262 res = 1;
1263 } else if (!strcasecmp(dialstatus, "ANSWER")) {
1264 res = 1;
1265 } else if (!strcasecmp(dialstatus, "CANCEL")) {
1266 res = 1;
1267 } else if (!strcasecmp(dialstatus, "DONTCALL")) {
1268 res = 1;
1269 } else if (!strcasecmp(dialstatus, "TORTURE")) {
1270 res = 1;
1271 } else if (!strcasecmp(dialstatus, "INVALIDARGS")) {
1272 res = 1;
1273 }
1274 return res;
1275}
1276
1277static void cel_dial_cb(void *data, struct stasis_subscription *sub,
1278 struct stasis_message *message)
1279{
1281 struct ast_channel_snapshot *snapshot;
1282
1283 snapshot = ast_multi_channel_blob_get_channel(blob, "caller");
1284 if (!snapshot || cel_filter_channel_snapshot(snapshot)) {
1285 return;
1286 }
1287
1288 if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
1289 struct ast_json *extra;
1290
1291 extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
1292 if (extra) {
1294 NULL, extra, NULL);
1295 ast_json_unref(extra);
1296 }
1297 }
1298
1299 if (is_valid_dialstatus(blob)) {
1300 save_dialstatus(blob, snapshot);
1301 }
1302}
1303
1304static void cel_generic_cb(
1305 void *data, struct stasis_subscription *sub,
1306 struct stasis_message *message)
1307{
1309 int event_type = ast_json_integer_get(ast_json_object_get(obj->blob, "event_type"));
1310 struct ast_json *event_details = ast_json_object_get(obj->blob, "event_details");
1311
1312 switch (event_type) {
1314 case AST_CEL_DTMF:
1316 {
1317 const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
1318 struct ast_json *extra = ast_json_object_get(event_details, "extra");
1320 event, extra, NULL);
1321 break;
1322 }
1323 case AST_CEL_STREAM_END:
1324 {
1325 const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
1327 event, NULL, NULL);
1328 break;
1329 }
1330 default:
1331 ast_log(LOG_ERROR, "Unhandled %s event blob\n", ast_cel_get_type_name(event_type));
1332 break;
1333 }
1334}
1335
1337 void *data, struct stasis_subscription *sub,
1338 struct stasis_message *message)
1339{
1341 struct ast_channel_snapshot *chan_snapshot = transfer_msg->transferer;
1342 struct ast_bridge_snapshot *bridge_snapshot = transfer_msg->bridge;
1343 struct ast_json *extra;
1344
1345 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
1346 return;
1347 }
1348
1349 extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
1350 "extension", transfer_msg->exten,
1351 "context", transfer_msg->context,
1352 "bridge_id", bridge_snapshot->uniqueid,
1353 "transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->base->name : "N/A",
1354 "transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->base->uniqueid : "N/A");
1355 if (extra) {
1357 NULL, extra, NULL);
1358 ast_json_unref(extra);
1359 }
1360}
1361
1363 void *data, struct stasis_subscription *sub,
1364 struct stasis_message *message)
1365{
1367 struct ast_json *extra = NULL;
1368 struct ast_bridge_snapshot *bridge1, *bridge2;
1369 struct ast_channel_snapshot *channel1, *channel2;
1370
1371 /* Make sure bridge1 is always non-NULL */
1372 if (!xfer->to_transferee.bridge_snapshot) {
1373 bridge1 = xfer->to_transfer_target.bridge_snapshot;
1374 bridge2 = xfer->to_transferee.bridge_snapshot;
1375 channel1 = xfer->to_transfer_target.channel_snapshot;
1376 channel2 = xfer->to_transferee.channel_snapshot;
1377 } else {
1378 bridge1 = xfer->to_transferee.bridge_snapshot;
1379 bridge2 = xfer->to_transfer_target.bridge_snapshot;
1380 channel1 = xfer->to_transferee.channel_snapshot;
1381 channel2 = xfer->to_transfer_target.channel_snapshot;
1382 }
1383
1384 switch (xfer->dest_type) {
1386 return;
1387 /* handle these three the same */
1391 extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
1392 "bridge1_id", bridge1->uniqueid,
1393 "channel2_name", channel2->base->name,
1394 "channel2_uniqueid", channel2->base->uniqueid,
1395 "bridge2_id", bridge2->uniqueid,
1396 "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
1397 "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
1398 "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
1399 "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
1400 if (!extra) {
1401 return;
1402 }
1403 break;
1406 extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
1407 "bridge1_id", bridge1->uniqueid,
1408 "channel2_name", channel2->base->name,
1409 "channel2_uniqueid", channel2->base->uniqueid,
1410 "app", xfer->dest.app,
1411 "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
1412 "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
1413 "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
1414 "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
1415 if (!extra) {
1416 return;
1417 }
1418 break;
1419 }
1421 NULL, extra, NULL);
1422 ast_json_unref(extra);
1423}
1424
1425static void cel_pickup_cb(
1426 void *data, struct stasis_subscription *sub,
1427 struct stasis_message *message)
1428{
1430 struct ast_channel_snapshot *channel = ast_multi_channel_blob_get_channel(obj, "channel");
1431 struct ast_channel_snapshot *target = ast_multi_channel_blob_get_channel(obj, "target");
1432 struct ast_json *extra;
1433
1434 if (!channel || !target) {
1435 return;
1436 }
1437
1438 extra = ast_json_pack("{s: s, s: s}",
1439 "pickup_channel", channel->base->name,
1440 "pickup_channel_uniqueid", channel->base->uniqueid);
1441 if (!extra) {
1442 return;
1443 }
1444
1446 ast_json_unref(extra);
1447}
1448
1449
1451 void *data, struct stasis_subscription *sub,
1452 struct stasis_message *message,
1453 enum ast_cel_event_type event_type)
1454{
1456 struct ast_channel_snapshot *localone = ast_multi_channel_blob_get_channel(obj, "1");
1457 struct ast_channel_snapshot *localtwo = ast_multi_channel_blob_get_channel(obj, "2");
1458 struct ast_json *extra;
1459
1460 if (!localone || !localtwo) {
1461 return;
1462 }
1463
1464 extra = ast_json_pack("{s: s, s: s}",
1465 "local_two", localtwo->base->name,
1466 "local_two_uniqueid", localtwo->base->uniqueid);
1467 if (!extra) {
1468 return;
1469 }
1470
1471 cel_report_event(localone, event_type, stasis_message_timestamp(message), NULL, extra, NULL);
1472 ast_json_unref(extra);
1473}
1474
1476 void *data, struct stasis_subscription *sub,
1477 struct stasis_message *message)
1478{
1479 /* The AST_CEL_LOCAL_OPTIMIZE event has always been triggered by the end of optimization.
1480 This can either be used as an indication that the call was locally optimized, or as
1481 the END event in combination with the subsequently added BEGIN event. */
1483}
1484
1491
1497
1510
1511static int unload_module(void)
1512{
1516
1518 aco_info_destroy(&cel_cfg_info);
1519 ao2_global_obj_release(cel_configs);
1520 ao2_global_obj_release(cel_dialstatus_store);
1521 ao2_global_obj_release(cel_linkedids);
1522 ao2_global_obj_release(cel_backends);
1523
1524 return 0;
1525}
1526
1527/*!
1528 * \brief Create the Stasis subscriptions for CEL
1529 */
1530static int create_subscriptions(void)
1531{
1532 cel_aggregation_topic = stasis_topic_create("cel:aggregator");
1533 if (!cel_aggregation_topic) {
1534 return -1;
1535 }
1536
1537 cel_topic = stasis_topic_create("cel:misc");
1538 if (!cel_topic) {
1539 return -1;
1540 }
1541
1545 if (!cel_channel_forwarder) {
1546 return -1;
1547 }
1548
1552 if (!cel_bridge_forwarder) {
1553 return -1;
1554 }
1555
1559 if (!cel_parking_forwarder) {
1560 return -1;
1561 }
1562
1564 ast_cel_topic(),
1566 if (!cel_cel_forwarder) {
1567 return -1;
1568 }
1569
1570 return 0;
1571}
1572
1573/*!
1574 * \brief Create the Stasis message router and routes for CEL
1575 */
1576static int create_routes(void)
1577{
1578 int ret = 0;
1579
1581 if (!cel_state_router) {
1582 return -1;
1583 }
1586
1590 NULL);
1591
1595 NULL);
1596
1600 NULL);
1601
1605 NULL);
1606
1610 NULL);
1611
1615 NULL);
1616
1620 NULL);
1621
1625 NULL);
1626
1630 NULL);
1631
1635 NULL);
1636
1640 NULL);
1641
1642 if (ret) {
1643 ast_log(AST_LOG_ERROR, "Failed to register for Stasis messages\n");
1644 }
1645
1646 return ret;
1647}
1648
1651
1652static int load_module(void)
1653{
1654 struct ao2_container *container;
1655
1657 NUM_APP_BUCKETS, cel_linkedid_hash_fn, NULL, cel_linkedid_cmp_fn);
1660 if (!container) {
1662 }
1663
1665 NUM_DIALSTATUS_BUCKETS, cel_dialstatus_hash_fn, NULL, cel_dialstatus_cmp_fn);
1666 ao2_global_obj_replace_unref(cel_dialstatus_store, container);
1668 if (!container) {
1670 }
1671
1674 }
1675
1678 }
1679
1681 cel_backend_hash_fn, NULL, cel_backend_cmp_fn);
1684 if (!container) {
1686 }
1687
1688 if (aco_info_init(&cel_cfg_info)) {
1690 }
1691
1692 aco_option_register(&cel_cfg_info, "enable", ACO_EXACT, general_options, "no", OPT_BOOL_T, 1, FLDSET(struct ast_cel_general_config, enable));
1693 aco_option_register(&cel_cfg_info, "dateformat", ACO_EXACT, general_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_cel_general_config, date_format));
1694 aco_option_register_custom(&cel_cfg_info, "apps", ACO_EXACT, general_options, "", apps_handler, 0);
1695 aco_option_register_custom(&cel_cfg_info, "events", ACO_EXACT, general_options, "", events_handler, 0);
1696
1697 if (aco_process_config(&cel_cfg_info, 0)) {
1698 struct cel_config *cel_cfg = cel_config_alloc();
1699
1700 if (!cel_cfg) {
1702 }
1703
1704 /* We couldn't process the configuration so create a default config. */
1705 if (!aco_set_defaults(&general_option, "general", cel_cfg->general)) {
1706 ast_log(LOG_NOTICE, "Failed to process CEL configuration; using defaults\n");
1707 ao2_global_obj_replace_unref(cel_configs, cel_cfg);
1708 }
1709 ao2_ref(cel_cfg, -1);
1710 }
1711
1712 if (create_subscriptions()) {
1714 }
1715
1718 }
1719
1721}
1722
1723static int reload_module(void)
1724{
1725 unsigned int was_enabled = ast_cel_check_enabled();
1726 unsigned int is_enabled;
1727
1728 if (aco_process_config(&cel_cfg_info, 1) == ACO_PROCESS_ERROR) {
1729 return -1;
1730 }
1731
1733
1734 if (!was_enabled && is_enabled) {
1735 if (create_routes()) {
1736 return -1;
1737 }
1738 } else if (was_enabled && !is_enabled) {
1740 }
1741
1742 ast_verb(3, "CEL logging %sabled.\n", is_enabled ? "en" : "dis");
1743
1744 return 0;
1745}
1746
1748 const char *event,
1749 const char *extra)
1750{
1751 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1752
1753 blob = ast_json_pack("{s: s, s: {s: s}}",
1754 "event", event,
1755 "extra", "extra", S_OR(extra, ""));
1756 if (!blob) {
1757 return;
1758 }
1760}
1761
1763 enum ast_cel_event_type event_type,
1764 struct ast_json *blob)
1765{
1766 struct ast_json *cel_blob;
1767 struct stasis_message *message;
1768
1769 cel_blob = ast_json_pack("{s: i, s: o}",
1770 "event_type", event_type,
1771 "event_details", ast_json_ref(blob));
1772
1774 if (message) {
1776 }
1778 ast_json_unref(cel_blob);
1779}
1780
1782{
1783 return cel_topic;
1784}
1785
1787{
1788 RAII_VAR(struct cel_config *, mod_cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
1789
1790 if (!mod_cfg || !mod_cfg->general) {
1791 return NULL;
1792 }
1793
1794 ao2_ref(mod_cfg->general, +1);
1795 return mod_cfg->general;
1796}
1797
1799{
1800 int was_enabled;
1801 int is_enabled;
1802 struct ast_cel_general_config *cleanup_config;
1803 struct cel_config *mod_cfg = ao2_global_obj_ref(cel_configs);
1804
1805 if (mod_cfg) {
1806 was_enabled = ast_cel_check_enabled();
1807
1808 cleanup_config = mod_cfg->general;
1810 mod_cfg->general = config;
1811 ao2_cleanup(cleanup_config);
1812
1814 if (!was_enabled && is_enabled) {
1815 create_routes();
1816 } else if (was_enabled && !is_enabled) {
1818 }
1819
1820 ao2_ref(mod_cfg, -1);
1821 }
1822}
1823
1825{
1826 struct ao2_container *backends = ao2_global_obj_ref(cel_backends);
1827
1828 if (backends) {
1830 ao2_ref(backends, -1);
1831 }
1832
1833 return 0;
1834}
1835
1836int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
1837{
1839 struct cel_backend *backend;
1840
1841 if (!backends || ast_strlen_zero(name) || !backend_callback) {
1842 return -1;
1843 }
1844
1845 /* The backend object is immutable so it doesn't need a lock of its own. */
1846 backend = ao2_alloc_options(sizeof(*backend) + 1 + strlen(name), NULL,
1848 if (!backend) {
1849 return -1;
1850 }
1851 strcpy(backend->name, name);/* Safe */
1852 backend->callback = backend_callback;
1853
1854 ao2_link(backends, backend);
1855 ao2_ref(backend, -1);
1856 return 0;
1857}
1858
1860 .support_level = AST_MODULE_SUPPORT_CORE,
1861 .load = load_module,
1862 .unload = unload_module,
1864 .load_pri = AST_MODPRI_CORE,
1865 .requires = "extconfig",
static const char app[]
static const struct adsi_event events[]
#define var
Definition ast_expr2f.c:605
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition astmm.c:1739
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define AO2_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
Definition astobj2.h:847
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition astobj2.h:901
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define AO2_STRING_FIELD_CMP_FN(stype, field)
Creates a compare function for a structure string field.
Definition astobj2.h:2048
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition astobj2.h:1578
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition astobj2.h:918
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition astobj2.h:859
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
#define AO2_STRING_FIELD_HASH_FN(stype, field)
Creates a hash function for a structure string field.
Definition astobj2.h:2032
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_UNLINK
Definition astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
Bridging API.
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition bridge.h:1104
static void destroy_routes(void)
Definition cel.c:1492
void ast_cel_publish_user_event(struct ast_channel *chan, const char *event, const char *extra)
Publish a CEL user event.
Definition cel.c:1747
static struct aco_type ignore_option
Definition cel.c:275
void ast_cel_set_config(struct ast_cel_general_config *config)
Set the current CEL configuration.
Definition cel.c:1798
static int cel_linkedid_ref(const char *linkedid)
Definition cel.c:832
static void cel_general_config_dtor(void *obj)
Destructor for cel_config.
Definition cel.c:199
static const char * ignore_categories[]
Definition cel.c:269
#define BACKEND_BUCKETS
Definition cel.c:160
static struct ast_cli_entry cli_status
Definition cel.c:439
static struct stasis_forward * cel_cel_forwarder
Definition cel.c:151
static int cel_format_eventtime(struct cel_config *cfg, struct timeval eventtime, char *timebuf, size_t len)
Definition cel.c:676
static int cel_report_event(struct ast_channel_snapshot *snapshot, enum ast_cel_event_type event_type, const struct timeval *event_time, const char *userdefevname, struct ast_json *extra, const char *peer_str)
Definition cel.c:593
static int ast_cel_track_event(enum ast_cel_event_type et)
Definition cel.c:455
#define CEL_MAX_EVENT_IDS
Maximum possible CEL event IDs.
Definition cel.c:169
static int create_subscriptions(void)
Create the Stasis subscriptions for CEL.
Definition cel.c:1530
static void cel_local_optimization_end_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1475
int ast_cel_backend_unregister(const char *name)
Unregister a CEL backend.
Definition cel.c:1824
static const char *const cel_event_types[CEL_MAX_EVENT_IDS]
Map of ast_cel_event_type to strings.
Definition cel.c:324
void(* cel_channel_snapshot_monitor)(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot, const struct timeval *event_time)
Typedef for callbacks that get called on channel snapshot updates.
Definition cel.c:911
struct ast_event * ast_cel_create_event(struct ast_channel_snapshot *snapshot, enum ast_cel_event_type event_type, const char *userdefevname, struct ast_json *extra, const char *peer)
Allocate and populate a CEL event structure.
Definition cel.c:540
static int create_routes(void)
Create the Stasis message router and routes for CEL.
Definition cel.c:1576
static int is_valid_dialstatus(struct ast_multi_channel_blob *blob)
Definition cel.c:1248
static struct aco_type general_option
An aco_type structure to link the "general" category to the ast_cel_general_config type.
Definition cel.c:260
enum ast_cel_event_type ast_cel_str_to_event_type(const char *name)
Get the event type from a string.
Definition cel.c:441
void ast_cel_publish_event(struct ast_channel *chan, enum ast_cel_event_type event_type, struct ast_json *blob)
Publish a CEL event.
Definition cel.c:1762
static void cel_channel_linkedid_change(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot, const struct timeval *event_time)
Definition cel.c:984
static void cel_bridge_leave_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1125
static void cel_dial_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1277
static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1042
static int events_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition cel.c:466
void * ast_cel_general_config_alloc(void)
Allocate a CEL configuration object.
Definition cel.c:207
int ast_cel_format_eventtime(struct timeval eventtime, char *timebuf, size_t len)
Format an event timeval using dateformat from cel.conf.
Definition cel.c:694
unsigned int ast_cel_check_enabled(void)
Hashing function for cel_backend.
Definition cel.c:366
#define NUM_DIALSTATUS_BUCKETS
Number of buckets for the dialstatus container.
Definition cel.c:179
static struct aco_file cel_conf
The config file to be processed for the module.
Definition cel.c:283
static int reload_module(void)
Definition cel.c:1723
static void check_retire_linkedid(struct ast_channel_snapshot *snapshot, const struct timeval *event_time)
Definition cel.c:638
static int cel_filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
Definition cel.c:1034
static void cel_pickup_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1425
static void cel_blind_transfer_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1336
static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_channel_snapshot *snapshot)
Definition cel.c:1204
struct stasis_topic * ast_cel_topic(void)
Get the CEL topic.
Definition cel.c:1781
static struct aco_type * general_options[]
Definition cel.c:319
static void cel_config_dtor(void *obj)
Destructor for cel_config.
Definition cel.c:236
static void cel_attended_transfer_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1362
static int cel_track_app(const char *const_app)
Definition cel.c:519
struct ast_channel * ast_cel_fabricate_channel_from_event(const struct ast_event *event)
Create a fake channel from data in a CEL event.
Definition cel.c:717
int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *r)
Fill in an ast_cel_event_record from a CEL event.
Definition cel.c:870
static const char * get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
Definition cel.c:928
static int cel_pre_apply_config(void)
Definition cel.c:295
static void cel_channel_state_change(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot, const struct timeval *event_time)
Handle channel state changes.
Definition cel.c:944
static struct stasis_forward * cel_channel_forwarder
Definition cel.c:142
cel_channel_snapshot_monitor cel_channel_monitors[]
Handlers for channel snapshot changes.
Definition cel.c:1028
struct stasis_message_type * cel_generic_type(void)
static char * handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition cel.c:376
static int load_module(void)
Definition cel.c:1652
static int cel_backend_send_cb(void *obj, void *arg, int flags)
Definition cel.c:585
static void cel_channel_app_change(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot, const struct timeval *event_time)
Definition cel.c:1003
static int apps_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition cel.c:495
static struct ast_str * cel_generate_peer_str(struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *chan)
Definition cel.c:1057
#define NUM_APP_BUCKETS
Number of buckets for the appset container.
Definition cel.c:174
static const struct ast_datastore_info fabricated_channel_datastore
Definition cel.c:712
static void cel_generic_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1304
static struct stasis_forward * cel_bridge_forwarder
Definition cel.c:145
static void cel_parking_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1155
static struct stasis_message_router * cel_state_router
Definition cel.c:133
static struct stasis_topic * cel_topic
Definition cel.c:136
static int unload_module(void)
Definition cel.c:1511
static struct cel_dialstatus * get_dialstatus(const char *uniqueid)
Definition cel.c:916
struct ast_cel_general_config * ast_cel_get_config(void)
Obtain the current CEL configuration.
Definition cel.c:1786
static void * cel_config_alloc(void)
Definition cel.c:243
int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
Register a CEL backend.
Definition cel.c:1836
const char * ast_cel_get_type_name(enum ast_cel_event_type type)
Get the name of a CEL event type.
Definition cel.c:514
static void destroy_subscriptions(void)
Definition cel.c:1498
static struct stasis_forward * cel_parking_forwarder
Definition cel.c:148
struct ast_event * ast_cel_create_event_with_time(struct ast_channel_snapshot *snapshot, enum ast_cel_event_type event_type, const struct timeval *event_time, const char *userdefevname, struct ast_json *extra, const char *peer)
Allocate and populate a CEL event structure.
Definition cel.c:550
static void cel_local_optimization_begin_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1485
static void cel_bridge_enter_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cel.c:1095
static struct stasis_topic * cel_aggregation_topic
Definition cel.c:139
static void cel_local_optimization_cb_helper(void *data, struct stasis_subscription *sub, struct stasis_message *message, enum ast_cel_event_type event_type)
Definition cel.c:1450
Call Event Logging API.
ast_cel_event_type
CEL event types.
Definition cel.h:42
@ AST_CEL_CHANNEL_END
channel end
Definition cel.h:48
@ AST_CEL_APP_END
an app ends
Definition cel.h:56
@ AST_CEL_ANSWER
A ringing phone is answered.
Definition cel.h:52
@ AST_CEL_PARK_START
a channel is parked
Definition cel.h:62
@ AST_CEL_LINKEDID_END
the last channel with the given linkedid is retired
Definition cel.h:72
@ AST_CEL_INVALID_VALUE
Definition cel.h:43
@ AST_CEL_BRIDGE_EXIT
channel exits a bridge
Definition cel.h:60
@ AST_CEL_FORWARD
this call was forwarded somewhere else
Definition cel.h:76
@ AST_CEL_HANGUP
hangup terminates connection
Definition cel.h:50
@ AST_CEL_USER_DEFINED
a user-defined event, the event name field should be set
Definition cel.h:70
@ AST_CEL_PICKUP
a directed pickup was performed on this channel
Definition cel.h:74
@ AST_CEL_APP_START
an app starts
Definition cel.h:54
@ AST_CEL_LOCAL_OPTIMIZE_BEGIN
A local channel optimization has begun.
Definition cel.h:80
@ AST_CEL_ALL
Definition cel.h:44
@ AST_CEL_DTMF
A DTMF digit was processed.
Definition cel.h:86
@ AST_CEL_PARK_END
channel out of the park
Definition cel.h:64
@ AST_CEL_CHANNEL_START
channel birth
Definition cel.h:46
@ AST_CEL_STREAM_BEGIN
A stream started.
Definition cel.h:82
@ AST_CEL_ATTENDEDTRANSFER
a transfer occurs
Definition cel.h:68
@ AST_CEL_BRIDGE_ENTER
channel enters a bridge
Definition cel.h:58
@ AST_CEL_STREAM_END
A stream ended.
Definition cel.h:84
@ AST_CEL_BLINDTRANSFER
a transfer occurs
Definition cel.h:66
@ AST_CEL_LOCAL_OPTIMIZE
A local channel optimization occurred, this marks the end.
Definition cel.h:78
void(* ast_cel_backend_cb)(struct ast_event *event)
CEL backend callback.
Definition cel.h:330
#define AST_CEL_EVENT_RECORD_VERSION
struct ABI version
Definition cel.h:162
static const char type[]
static const char config[]
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
void ast_channel_appl_set(struct ast_channel *chan, const char *value)
void ast_channel_internal_set_fake_ids(struct ast_channel *chan, const char *uniqueid, const char *linkedid)
Set uniqueid and linkedid string value only (not time)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2376
struct varshead * ast_channel_varshead(struct ast_channel *chan)
void ast_channel_tenantid_set(struct ast_channel *chan, const char *value)
void ast_channel_data_set(struct ast_channel *chan, const char *value)
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3018
#define AST_MAX_UNIQUEID
Definition channel.h:170
void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition channel.h:1328
@ AST_FLAG_DEAD
Definition channel.h:1065
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition channel.h:991
void ast_channel_name_set(struct ast_channel *chan, const char *value)
@ AST_STATE_UP
#define ast_var_assign(name, value)
Definition chanvars.h:40
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
int ast_cli_unregister(struct ast_cli_entry *e)
Unregisters a command or an array of commands.
Definition main/cli.c:2516
#define ast_cli_register(e)
Registers a command or an array of commands.
Definition cli.h:256
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_HANDLER
Definition cli.h:154
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
Definition codec_g726.c:367
Configuration option-handling.
@ ACO_EXACT
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define ACO_FILES(...)
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
@ ACO_GLOBAL
@ ACO_IGNORE
@ ACO_WHITELIST_ARRAY
@ ACO_WHITELIST_EXACT
#define CONFIG_INFO_CORE(mod, name, arr, alloc,...)
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
Local proxy channel special access.
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition datastore.c:68
static int enabled
Definition dnsmgr.c:91
struct ast_event * ast_event_new(enum ast_event_type event_type,...)
Create a new event.
Definition event.c:403
uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has an integer payload.
Definition event.c:294
void ast_event_destroy(struct ast_event *event)
Destroy an event.
Definition event.c:525
const char * ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has a string payload.
Definition event.c:303
@ AST_EVENT_IE_CEL_ACCTCODE
Channel Event AccountCode Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:205
@ AST_EVENT_IE_END
Definition event_defs.h:70
@ AST_EVENT_IE_CEL_EXTRA
Channel Event extra data Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:259
@ AST_EVENT_IE_CEL_CONTEXT
Channel Event context name Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:175
@ AST_EVENT_IE_CEL_PEERACCT
Channel Event peeraccount Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:253
@ AST_EVENT_IE_CEL_CIDRDNIS
Channel Event CID RDNIS field Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:229
@ AST_EVENT_IE_CEL_EVENT_TIME
Channel Event Time (seconds) Used by: AST_EVENT_CEL Payload type: UINT.
Definition event_defs.h:139
@ AST_EVENT_IE_CEL_CHANNAME
Channel Event channel name Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:181
@ AST_EVENT_IE_CEL_CIDANI
Channel Event CID ANI field Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:223
@ AST_EVENT_IE_CEL_CIDDNID
Channel Event CID dnid Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:235
@ AST_EVENT_IE_CEL_EXTEN
Channel Event extension name Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:169
@ AST_EVENT_IE_CEL_CIDNAME
Channel Event CID name Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:157
@ AST_EVENT_IE_CEL_AMAFLAGS
Channel Event AMA flags Used by: AST_EVENT_CEL Payload type: UINT.
Definition event_defs.h:199
@ AST_EVENT_IE_CEL_USEREVENT_NAME
Channel Event User Event Name Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:151
@ AST_EVENT_IE_CEL_TENANTID
Channel Event TenantID Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:320
@ AST_EVENT_IE_CEL_LINKEDID
Channel Event LinkedID Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:247
@ AST_EVENT_IE_CEL_EVENT_TIME_USEC
Channel Event Time (micro-seconds) Used by: AST_EVENT_CEL Payload type: UINT.
Definition event_defs.h:145
@ AST_EVENT_IE_CEL_EVENT_TYPE
Channel Event Type Used by: AST_EVENT_CEL Payload type: UINT.
Definition event_defs.h:133
@ AST_EVENT_IE_CEL_UNIQUEID
Channel Event UniqueID Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:211
@ AST_EVENT_IE_CEL_APPNAME
Channel Event app name Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:187
@ AST_EVENT_IE_CEL_APPDATA
Channel Event app args/data Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:193
@ AST_EVENT_IE_CEL_PEER
Channel Event Peer – for Things involving multiple channels, like BRIDGE Used by: AST_EVENT_CEL Paylo...
Definition event_defs.h:241
@ AST_EVENT_IE_CEL_CIDNUM
Channel Event CID num Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:163
@ AST_EVENT_IE_CEL_USERFIELD
Channel Event Userfield Used by: AST_EVENT_CEL Payload type: STR.
Definition event_defs.h:217
@ AST_EVENT_CEL
Definition event_defs.h:50
@ AST_EVENT_IE_PLTYPE_UINT
Definition event_defs.h:333
@ AST_EVENT_IE_PLTYPE_STR
Definition event_defs.h:335
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)
struct stasis_topic * ast_parking_topic(void)
accessor for the parking stasis topic
Definition parking.c:67
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct stasis_message_type * ast_parked_call_type(void)
accessor for the parked call stasis message type
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
struct stasis_message_type * ast_channel_dial_type(void)
Message type for when a channel dials another channel.
struct stasis_message_type * ast_channel_snapshot_type(void)
Message type for ast_channel_snapshot_update.
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
Configuration File Parser.
Support for logging to various files, console and syslog Configuration in file logger....
#define AST_LOG_ERROR
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
Definition json.c:52
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition json.h:810
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition json.c:67
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition json.c:332
A set of macros to manage forward-linked lists.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition localtime.c:2524
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition module.h:330
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_CORE
Definition module.h:338
@ AST_MODULE_SUPPORT_CORE
Definition module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
@ AST_MODULE_LOAD_FAILURE
Module could not be loaded properly.
Definition module.h:102
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
Call Parking API.
@ PARKED_CALL
Definition parking.h:47
@ PARKED_CALL_TIMEOUT
Definition parking.h:48
@ PARKED_CALL_UNPARKED
Definition parking.h:50
@ PARKED_CALL_FAILED
Definition parking.h:51
@ PARKED_CALL_GIVEUP
Definition parking.h:49
@ PARKED_CALL_SWAP
Definition parking.h:52
Core PBX routines and definitions.
Call Pickup API.
struct stasis_message_type * ast_call_pickup_type(void)
accessor for call pickup message type
static int is_enabled(void)
Helper function to check if module is enabled.
Definition res_ari.c:96
static struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
static int reload(void)
struct ao2_container * container
Definition res_fax.c:603
#define NULL
Definition resample.c:96
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1515
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition stasis.c:1615
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition stasis.c:684
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
Definition stasis.h:1440
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition stasis.c:1645
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1578
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
@ AST_ATTENDED_TRANSFER_DEST_FAIL
@ AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE
@ AST_ATTENDED_TRANSFER_DEST_LOCAL_APP
@ AST_ATTENDED_TRANSFER_DEST_LINK
@ AST_ATTENDED_TRANSFER_DEST_APP
@ AST_ATTENDED_TRANSFER_DEST_THREEWAY
struct stasis_message_type * ast_channel_left_bridge_type(void)
Message type for ast_channel leave bridge blob messages.
int stasis_message_router_set_congestion_limits(struct stasis_message_router *router, long low_water, long high_water)
Set the high and low alert water marks of the stasis message router.
#define stasis_message_router_create(topic)
Create a new message router object.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
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
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition strings.h:1321
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition strings.h:1365
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition strings.c:205
The representation of a single configuration file to be processed.
const char * filename
Type information about a category-level configurable object.
enum aco_type_t type
enum aco_category_op category_match
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
Registered applications container.
Definition pbx_app.c:69
Message representing attended transfer.
enum ast_attended_transfer_dest_type dest_type
union ast_attended_transfer_message::@301 dest
struct ast_bridge_channel_snapshot_pair to_transfer_target
struct ast_channel_snapshot * transferee
struct ast_bridge_channel_snapshot_pair to_transferee
struct ast_channel_snapshot * target
Message published during a blind transfer.
char exten[AST_MAX_EXTENSION]
struct ast_bridge_snapshot * bridge
struct ast_channel_snapshot * transferer
struct ast_channel_snapshot * transferee
enum ast_transfer_result result
char context[AST_MAX_CONTEXT]
Blob of data associated with a bridge.
struct ast_bridge_snapshot * bridge
struct ast_channel_snapshot * channel
struct ast_json * blob
struct ast_bridge_snapshot * bridge_snapshot
struct ast_channel_snapshot * channel_snapshot
Structure that contains a snapshot of information about a bridge.
Definition bridge.h:318
const ast_string_field uniqueid
Definition bridge.h:332
const ast_string_field technology
Definition bridge.h:332
struct ao2_container * channels
Definition bridge.h:335
Helper struct for getting the fields out of a CEL event.
Definition cel.h:157
const char * caller_id_dnid
Definition cel.h:176
const char * application_data
Definition cel.h:181
const char * account_code
Definition cel.h:182
const char * caller_id_rdnis
Definition cel.h:175
const char * extra
Definition cel.h:190
const char * extension
Definition cel.h:177
const char * caller_id_num
Definition cel.h:173
const char * channel_name
Definition cel.h:179
const char * linked_id
Definition cel.h:185
const char * peer_account
Definition cel.h:183
const char * peer
Definition cel.h:189
enum ast_cel_event_type event_type
Definition cel.h:168
const char * unique_id
Definition cel.h:184
const char * user_defined_name
Definition cel.h:171
const char * context
Definition cel.h:178
const char * application_name
Definition cel.h:180
struct timeval event_time
Definition cel.h:169
uint32_t version
struct ABI version
Definition cel.h:167
const char * tenant_id
Definition cel.h:186
const char * user_field
Definition cel.h:188
const char * caller_id_ani
Definition cel.h:174
const char * caller_id_name
Definition cel.h:172
const char * event_name
Definition cel.h:170
A structure to hold CEL global configuration options.
Definition cel.h:243
const ast_string_field date_format
Definition cel.h:246
struct ao2_container * apps
Definition cel.h:252
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
const ast_string_field tenantid
const ast_string_field accountcode
const ast_string_field userfield
const ast_string_field uniqueid
const ast_string_field name
const ast_string_field number
const ast_string_field rdnis
const ast_string_field ani
const ast_string_field name
const ast_string_field dnid
const ast_string_field data
const ast_string_field context
const ast_string_field exten
const ast_string_field appl
Structure representing a change of snapshot of channel state.
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_dialplan * dialplan
struct ast_channel_snapshot_peer * peer
struct ast_channel_snapshot_base * base
enum ast_channel_state state
struct ast_channel_snapshot_caller * caller
struct ast_flags flags
struct ast_channel_snapshot_hangup * hangup
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
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
void * data
Definition datastore.h:66
An event.
Definition event.c:81
Abstract JSON element (object, array, string, int, ...).
A multi channel blob data structure for multi_channel_blob stasis messages.
struct ast_json * blob
A parked call message payload.
Definition parking.h:59
const ast_string_field parkinglot
Definition parking.h:69
struct ast_channel_snapshot * retriever
Definition parking.h:61
struct ast_channel_snapshot * parkee
Definition parking.h:60
enum ast_parked_call_event_type event_type
Definition parking.h:62
const ast_string_field parker_dial_string
Definition parking.h:69
struct ast_party_id id
Caller party ID.
Definition channel.h:422
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition channel.h:429
char * str
Subscriber phone number (Malloced)
Definition channel.h:388
struct ast_party_dialed::@217 number
Dialed/Called number.
struct ast_party_name name
Subscriber name.
Definition channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition channel.h:281
char * str
Subscriber name (Malloced)
Definition channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition channel.h:299
char * str
Subscriber phone number (Malloced)
Definition channel.h:293
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition channel.h:529
Support for dynamic strings.
Definition strings.h:623
Structure for variables, used for configurations and for channel variables.
the list of registered channel types
Definition channel.c:125
ast_cel_backend_cb callback
Definition cel.c:350
char name[0]
Definition cel.c:351
A container that holds all config-related information.
Definition cel.c:228
struct ast_cel_general_config * general
Definition cel.c:229
char dialstatus[0]
Definition cel.c:195
char uniqueid[AST_MAX_UNIQUEID]
Definition cel.c:193
unsigned int count
Definition cel.c:183
char id[0]
Definition cel.c:185
Forwarding information.
Definition stasis.c:1598
An API for managing task processing threads that can be shared across modules.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
static struct test_val a
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
Utility functions.
#define ast_test_flag(p, flag)
Definition utils.h:64
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define ARRAY_LEN(a)
Definition utils.h:706