Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 </enumlist>
122 </description>
123 </configOption>
124 </configObject>
125 </configFile>
126 </configInfo>
127 ***/
128
129/*! Message router for state that CEL needs to know about */
131
132/*! Topic for CEL-specific messages */
133static struct stasis_topic *cel_topic;
134
135/*! Aggregation topic for all topics CEL needs to know about */
137
138/*! Subscription for forwarding the channel caching topic */
140
141/*! Subscription for forwarding the channel caching topic */
143
144/*! Subscription for forwarding the parking topic */
146
147/*! Subscription for forwarding the CEL-specific topic */
149
152
153/*! Container for CEL backend information */
154static AO2_GLOBAL_OBJ_STATIC(cel_backends);
155
156/*! The number of buckets into which backend names will be hashed */
157#define BACKEND_BUCKETS 13
158
159/*! Container for dial end multichannel blobs for holding on to dial statuses */
160static AO2_GLOBAL_OBJ_STATIC(cel_dialstatus_store);
161
162/*!
163 * \brief Maximum possible CEL event IDs
164 * \note This limit is currently imposed by the eventset definition
165 */
166#define CEL_MAX_EVENT_IDS 64
167
168/*!
169 * \brief Number of buckets for the appset container
170 */
171#define NUM_APP_BUCKETS 97
172
173/*!
174 * \brief Number of buckets for the dialstatus container
175 */
176#define NUM_DIALSTATUS_BUCKETS 251
177
179 /*! Number of channels with this linkedid. */
180 unsigned int count;
181 /*! Linkedid stored at end of struct. */
182 char id[0];
183};
184
185/*! Container of channel references to a linkedid for CEL purposes. */
186static AO2_GLOBAL_OBJ_STATIC(cel_linkedids);
187
189 /*! Uniqueid of the channel */
191 /*! The dial status */
192 char dialstatus[0];
193};
194
195/*! \brief Destructor for cel_config */
196static void cel_general_config_dtor(void *obj)
197{
198 struct ast_cel_general_config *cfg = obj;
200 ao2_cleanup(cfg->apps);
201 cfg->apps = NULL;
202}
203
205{
207
208 if (!(cfg = ao2_alloc(sizeof(*cfg), cel_general_config_dtor))) {
209 return NULL;
210 }
211
212 if (ast_string_field_init(cfg, 64)) {
213 return NULL;
214 }
215
216 if (!(cfg->apps = ast_str_container_alloc(NUM_APP_BUCKETS))) {
217 return NULL;
218 }
219
220 ao2_ref(cfg, +1);
221 return cfg;
222}
223
224/*! \brief A container that holds all config-related information */
225struct cel_config {
227};
228
229
230static AO2_GLOBAL_OBJ_STATIC(cel_configs);
231
232/*! \brief Destructor for cel_config */
233static void cel_config_dtor(void *obj)
234{
235 struct cel_config *cfg = obj;
236 ao2_cleanup(cfg->general);
237 cfg->general = NULL;
238}
239
240static void *cel_config_alloc(void)
241{
242 RAII_VAR(struct cel_config *, cfg, NULL, ao2_cleanup);
243
244 if (!(cfg = ao2_alloc(sizeof(*cfg), cel_config_dtor))) {
245 return NULL;
246 }
247
248 if (!(cfg->general = ast_cel_general_config_alloc())) {
249 return NULL;
250 }
251
252 ao2_ref(cfg, +1);
253 return cfg;
254}
255
256/*! \brief An aco_type structure to link the "general" category to the ast_cel_general_config type */
257static struct aco_type general_option = {
258 .type = ACO_GLOBAL,
259 .name = "general",
260 .item_offset = offsetof(struct cel_config, general),
261 .category_match = ACO_WHITELIST_EXACT,
262 .category = "general",
263};
264
265/*! Config sections used by existing modules. Do not add to this list. */
266static const char *ignore_categories[] = {
267 "manager",
268 "radius",
269 NULL,
270};
271
272static struct aco_type ignore_option = {
273 .type = ACO_IGNORE,
274 .name = "modules",
275 .category = (const char*)ignore_categories,
277};
278
279/*! \brief The config file to be processed for the module. */
280static struct aco_file cel_conf = {
281 .filename = "cel.conf", /*!< The name of the config file */
282 .types = ACO_TYPES(&general_option, &ignore_option), /*!< The mapping object types to be processed */
283};
284
285static int cel_pre_apply_config(void);
286
287CONFIG_INFO_CORE("cel", cel_cfg_info, cel_configs, cel_config_alloc,
288 .files = ACO_FILES(&cel_conf),
289 .pre_apply_config = cel_pre_apply_config,
290);
291
292static int cel_pre_apply_config(void)
293{
294 struct cel_config *cfg = aco_pending_config(&cel_cfg_info);
295
296 if (!cfg->general) {
297 return -1;
298 }
299
300 if (!ao2_container_count(cfg->general->apps)) {
301 return 0;
302 }
303
304 if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_START)) {
305 return 0;
306 }
307
308 if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_END)) {
309 return 0;
310 }
311
312 ast_log(LOG_ERROR, "Applications are listed to be tracked, but APP events are not tracked\n");
313 return -1;
314}
315
317
318/*!
319 * \brief Map of ast_cel_event_type to strings
320 */
321static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
322 [AST_CEL_ALL] = "ALL",
323 [AST_CEL_CHANNEL_START] = "CHAN_START",
324 [AST_CEL_CHANNEL_END] = "CHAN_END",
325 [AST_CEL_ANSWER] = "ANSWER",
326 [AST_CEL_HANGUP] = "HANGUP",
327 [AST_CEL_APP_START] = "APP_START",
328 [AST_CEL_APP_END] = "APP_END",
329 [AST_CEL_PARK_START] = "PARK_START",
330 [AST_CEL_PARK_END] = "PARK_END",
331 [AST_CEL_USER_DEFINED] = "USER_DEFINED",
332 [AST_CEL_BRIDGE_ENTER] = "BRIDGE_ENTER",
333 [AST_CEL_BRIDGE_EXIT] = "BRIDGE_EXIT",
334 [AST_CEL_BLINDTRANSFER] = "BLINDTRANSFER",
335 [AST_CEL_ATTENDEDTRANSFER] = "ATTENDEDTRANSFER",
336 [AST_CEL_PICKUP] = "PICKUP",
337 [AST_CEL_FORWARD] = "FORWARD",
338 [AST_CEL_LINKEDID_END] = "LINKEDID_END",
339 [AST_CEL_LOCAL_OPTIMIZE] = "LOCAL_OPTIMIZE",
340 [AST_CEL_LOCAL_OPTIMIZE_BEGIN] = "LOCAL_OPTIMIZE_BEGIN",
341};
342
344 ast_cel_backend_cb callback; /*!< Callback for this backend */
345 char name[0]; /*!< Name of this backend */
346};
347
348/*! \brief Hashing function for cel_backend */
350
351/*! \brief Comparator function for cel_backend */
353
354/*! \brief Hashing function for dialstatus container */
356
357/*! \brief Comparator function for dialstatus container */
359
360unsigned int ast_cel_check_enabled(void)
361{
362 unsigned int enabled;
363 struct cel_config *cfg = ao2_global_obj_ref(cel_configs);
364
365 enabled = (!cfg || !cfg->general) ? 0 : cfg->general->enable;
366 ao2_cleanup(cfg);
367 return enabled;
368}
369
370static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
371{
372 unsigned int i;
373 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
375 struct ao2_iterator iter;
376 char *app;
377
378 switch (cmd) {
379 case CLI_INIT:
380 e->command = "cel show status";
381 e->usage =
382 "Usage: cel show status\n"
383 " Displays the Channel Event Logging system status.\n";
384 return NULL;
385 case CLI_GENERATE:
386 return NULL;
387 case CLI_HANDLER:
388 break;
389 }
390
391 if (a->argc > 3) {
392 return CLI_SHOWUSAGE;
393 }
394
395 ast_cli(a->fd, "CEL Logging: %s\n", ast_cel_check_enabled() ? "Enabled" : "Disabled");
396
397 if (!cfg || !cfg->general || !cfg->general->enable) {
398 return CLI_SUCCESS;
399 }
400
401 for (i = 0; i < (sizeof(cfg->general->events) * 8); i++) {
402 const char *name;
403
404 if (!(cfg->general->events & ((int64_t) 1 << i))) {
405 continue;
406 }
407
409 if (strcasecmp(name, "Unknown")) {
410 ast_cli(a->fd, "CEL Tracking Event: %s\n", name);
411 }
412 }
413
414 iter = ao2_iterator_init(cfg->general->apps, 0);
415 for (; (app = ao2_iterator_next(&iter)); ao2_ref(app, -1)) {
416 ast_cli(a->fd, "CEL Tracking Application: %s\n", app);
417 }
419
420 if (backends) {
421 struct cel_backend *backend;
422
423 iter = ao2_iterator_init(backends, 0);
424 for (; (backend = ao2_iterator_next(&iter)); ao2_ref(backend, -1)) {
425 ast_cli(a->fd, "CEL Event Subscriber: %s\n", backend->name);
426 }
428 }
429
430 return CLI_SUCCESS;
431}
432
433static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CEL status");
434
436{
437 unsigned int i;
438
439 for (i = 0; i < ARRAY_LEN(cel_event_types); i++) {
440 if (cel_event_types[i] && !strcasecmp(name, cel_event_types[i])) {
441 return i;
442 }
443 }
444
445 ast_log(LOG_ERROR, "Unknown event name '%s'\n", name);
447}
448
450{
451 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
452
453 if (!cfg || !cfg->general) {
454 return 0;
455 }
456
457 return (cfg->general->events & ((int64_t) 1 << et)) ? 1 : 0;
458}
459
460static int events_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
461{
462 struct ast_cel_general_config *cfg = obj;
463 char *events = ast_strdupa(var->value);
464 char *cur_event;
465
466 while ((cur_event = strsep(&events, ","))) {
467 enum ast_cel_event_type event_type;
468
469 cur_event = ast_strip(cur_event);
470 if (ast_strlen_zero(cur_event)) {
471 continue;
472 }
473
474 event_type = ast_cel_str_to_event_type(cur_event);
475
476 if (event_type == AST_CEL_ALL) {
477 /* All events */
478 cfg->events = (int64_t) -1;
479 } else if (event_type == AST_CEL_INVALID_VALUE) {
480 return -1;
481 } else {
482 cfg->events |= ((int64_t) 1 << event_type);
483 }
484 }
485
486 return 0;
487}
488
489static int apps_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
490{
491 struct ast_cel_general_config *cfg = obj;
492 char *apps = ast_strdupa(var->value);
493 char *cur_app;
494
495 while ((cur_app = strsep(&apps, ","))) {
496 cur_app = ast_strip(cur_app);
497 if (ast_strlen_zero(cur_app)) {
498 continue;
499 }
500
501 cur_app = ast_str_to_lower(cur_app);
502 ast_str_container_add(cfg->apps, cur_app);
503 }
504
505 return 0;
506}
507
509{
510 return S_OR(cel_event_types[type], "Unknown");
511}
512
513static int cel_track_app(const char *const_app)
514{
515 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
516 RAII_VAR(char *, app, NULL, ao2_cleanup);
517 char *app_lower;
518
519 if (!cfg || !cfg->general) {
520 return 0;
521 }
522
523 app_lower = ast_str_to_lower(ast_strdupa(const_app));
524 app = ao2_find(cfg->general->apps, app_lower, OBJ_SEARCH_KEY);
525 if (!app) {
526 return 0;
527 }
528
529 return 1;
530}
531
532static int cel_linkedid_ref(const char *linkedid);
533
535 enum ast_cel_event_type event_type, const char *userdefevname,
536 struct ast_json *extra, const char *peer)
537{
538 struct timeval eventtime = ast_tvnow();
539
540 return ast_cel_create_event_with_time(snapshot, event_type, &eventtime,
541 userdefevname, extra, peer);
542}
543
545 enum ast_cel_event_type event_type, const struct timeval *event_time,
546 const char *userdefevname, struct ast_json *extra, const char *peer)
547{
548 RAII_VAR(char *, extra_txt, NULL, ast_json_free);
549 if (extra) {
550 extra_txt = ast_json_dump_string(extra);
551 }
577}
578
579static int cel_backend_send_cb(void *obj, void *arg, int flags)
580{
581 struct cel_backend *backend = obj;
582
583 backend->callback(arg);
584 return 0;
585}
586
587static int cel_report_event(struct ast_channel_snapshot *snapshot,
588 enum ast_cel_event_type event_type, const struct timeval *event_time,
589 const char *userdefevname, struct ast_json *extra,
590 const char *peer_str)
591{
592 struct ast_event *ev;
593 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
595
596 if (!cfg || !cfg->general || !cfg->general->enable || !backends) {
597 return 0;
598 }
599
600 /* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
601 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
602 if (event_type == AST_CEL_CHANNEL_START
604 if (cel_linkedid_ref(snapshot->peer->linkedid)) {
605 return -1;
606 }
607 }
608
609 if (!ast_cel_track_event(event_type)) {
610 return 0;
611 }
612
613 if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
614 && !cel_track_app(snapshot->dialplan->appl)) {
615 return 0;
616 }
617
618 ev = ast_cel_create_event_with_time(snapshot, event_type, event_time, userdefevname, extra, peer_str);
619 if (!ev) {
620 return -1;
621 }
622
623 /* Distribute event to backends */
626
627 return 0;
628}
629
630/* called whenever a channel is destroyed or a linkedid is changed to
631 * potentially emit a CEL_LINKEDID_END event */
632static void check_retire_linkedid(struct ast_channel_snapshot *snapshot, const struct timeval *event_time)
633{
634 RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
635 struct cel_linkedid *lid;
636
637 if (!linkedids || ast_strlen_zero(snapshot->peer->linkedid)) {
638 /* The CEL module is shutdown. Abort. */
639 return;
640 }
641
642 ao2_lock(linkedids);
643
644 lid = ao2_find(linkedids, (void *) snapshot->peer->linkedid, OBJ_SEARCH_KEY);
645 if (!lid) {
646 ao2_unlock(linkedids);
647
648 /*
649 * The user may have done a reload to start tracking linkedids
650 * when a call was already in progress. This is an unusual kind
651 * of change to make after starting Asterisk.
652 */
653 ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n",
654 snapshot->peer->linkedid);
655 return;
656 }
657
658 if (!--lid->count) {
659 /* No channels use this linkedid anymore. */
660 ao2_unlink(linkedids, lid);
661 ao2_unlock(linkedids);
662
663 cel_report_event(snapshot, AST_CEL_LINKEDID_END, event_time, NULL, NULL, NULL);
664 } else {
665 ao2_unlock(linkedids);
666 }
667 ao2_ref(lid, -1);
668}
669
670/* Note that no 'chan_fixup' function is provided for this datastore type,
671 * because the channels that will use it will never be involved in masquerades.
672 */
674 .type = "CEL fabricated channel",
675 .destroy = ast_free_ptr,
676};
677
679{
680 struct varshead *headp;
681 struct ast_var_t *newvariable;
682 const char *mixed_name;
683 char timebuf[30];
684 struct ast_channel *tchan;
685 struct ast_cel_event_record record = {
687 };
688 struct ast_datastore *datastore;
689 char *app_data;
690 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
691
692 if (!cfg || !cfg->general) {
693 return NULL;
694 }
695
696 /* do not call ast_channel_alloc because this is not really a real channel */
697 if (!(tchan = ast_dummy_channel_alloc())) {
698 return NULL;
699 }
700
701 headp = ast_channel_varshead(tchan);
702
703 /* first, get the variables from the event */
704 if (ast_cel_fill_record(event, &record)) {
705 ast_channel_unref(tchan);
706 return NULL;
707 }
708
709 /* next, fill the channel with their data */
710 mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
711 ? record.user_defined_name : record.event_name;
712 if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
713 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
714 }
715
716 if (ast_strlen_zero(cfg->general->date_format)) {
717 snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
718 (long) record.event_time.tv_usec);
719 } else {
720 struct ast_tm tm;
721 ast_localtime(&record.event_time, &tm, NULL);
722 ast_strftime(timebuf, sizeof(timebuf), cfg->general->date_format, &tm);
723 }
724
725 if ((newvariable = ast_var_assign("eventtime", timebuf))) {
726 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
727 }
728
729 if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
730 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
731 }
732 if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
733 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
734 }
735 if ((newvariable = ast_var_assign("eventextra", record.extra))) {
736 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
737 }
738
739 ast_channel_caller(tchan)->id.name.valid = 1;
741 ast_channel_caller(tchan)->id.number.valid = 1;
748
749 ast_channel_exten_set(tchan, record.extension);
750 ast_channel_context_set(tchan, record.context);
751 ast_channel_name_set(tchan, record.channel_name);
753 ast_channel_accountcode_set(tchan, record.account_code);
754 ast_channel_peeraccount_set(tchan, record.peer_account);
755 ast_channel_userfield_set(tchan, record.user_field);
756
757 if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
758 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
759 }
760
761 ast_channel_amaflags_set(tchan, record.amaflag);
762
763 /* We need to store an 'application name' and 'application
764 * data' on the channel for logging purposes, but the channel
765 * structure only provides a place to store pointers, and it
766 * expects these pointers to be pointing to data that does not
767 * need to be freed. This means that the channel's destructor
768 * does not attempt to free any storage that these pointers
769 * point to. However, we can't provide data in that form directly for
770 * these structure members. In order to ensure that these data
771 * elements have a lifetime that matches the channel's
772 * lifetime, we'll put them in a datastore attached to the
773 * channel, and set's the channel's pointers to point into the
774 * datastore. The datastore will then be automatically destroyed
775 * when the channel is destroyed.
776 */
777
779 ast_channel_unref(tchan);
780 return NULL;
781 }
782
783 if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
784 ast_datastore_free(datastore);
785 ast_channel_unref(tchan);
786 return NULL;
787 }
788
789 ast_channel_appl_set(tchan, strcpy(app_data, record.application_name));
790 ast_channel_data_set(tchan, strcpy(app_data + strlen(record.application_name) + 1,
791 record.application_data));
792
793 datastore->data = app_data;
794 ast_channel_datastore_add(tchan, datastore);
795
796 return tchan;
797}
798
799static int cel_linkedid_ref(const char *linkedid)
800{
801 RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
802 struct cel_linkedid *lid;
803
804 if (ast_strlen_zero(linkedid)) {
805 ast_log(LOG_ERROR, "The linkedid should never be empty\n");
806 return -1;
807 }
808 if (!linkedids) {
809 /* The CEL module is shutdown. Abort. */
810 return -1;
811 }
812
813 ao2_lock(linkedids);
814 lid = ao2_find(linkedids, (void *) linkedid, OBJ_SEARCH_KEY);
815 if (!lid) {
816 /*
817 * Changes to the lid->count member are protected by the
818 * container lock so the lid object does not need its own lock.
819 */
820 lid = ao2_alloc_options(sizeof(*lid) + strlen(linkedid) + 1, NULL,
822 if (!lid) {
823 ao2_unlock(linkedids);
824 return -1;
825 }
826 strcpy(lid->id, linkedid);/* Safe */
827
828 ao2_link(linkedids, lid);
829 }
830 ++lid->count;
831 ao2_unlock(linkedids);
832 ao2_ref(lid, -1);
833
834 return 0;
835}
836
838{
840 ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record. "
841 "Please ensure all modules were compiled for "
842 "this version of Asterisk.\n");
843 return -1;
844 }
845
847
850
854 } else {
855 r->user_defined_name = "";
856 }
857
877
878 return 0;
879}
880
881/*! \brief Typedef for callbacks that get called on channel snapshot updates */
883 struct ast_channel_snapshot *old_snapshot,
884 struct ast_channel_snapshot *new_snapshot,
885 const struct timeval *event_time);
886
887static struct cel_dialstatus *get_dialstatus(const char *uniqueid)
888{
889 struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
891
892 if (dial_statuses) {
894 ao2_ref(dial_statuses, -1);
895 }
896 return dialstatus;
897}
898
899static const char *get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
900{
901 struct ast_json *json = ast_multi_channel_blob_get_json(blob);
902 if (!json) {
903 return NULL;
904 }
905
906 json = ast_json_object_get(json, varname);
907 if (!json) {
908 return NULL;
909 }
910
911 return ast_json_string_get(json);
912}
913
914/*! \brief Handle channel state changes */
916 struct ast_channel_snapshot *old_snapshot,
917 struct ast_channel_snapshot *new_snapshot,
918 const struct timeval *event_time)
919{
920 int is_hungup, was_hungup;
921
922 if (!old_snapshot) {
923 cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, event_time, NULL, NULL, NULL);
924 return;
925 }
926
927 was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
928 is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
929
930 if (!was_hungup && is_hungup) {
931 struct ast_json *extra;
932 struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->base->uniqueid);
933
934 extra = ast_json_pack("{s: i, s: s, s: s}",
935 "hangupcause", new_snapshot->hangup->cause,
936 "hangupsource", new_snapshot->hangup->source,
937 "dialstatus", dialstatus ? dialstatus->dialstatus : "");
938 cel_report_event(new_snapshot, AST_CEL_HANGUP, event_time, NULL, extra, NULL);
939 ast_json_unref(extra);
941
942 cel_report_event(new_snapshot, AST_CEL_CHANNEL_END, event_time, NULL, NULL, NULL);
944 check_retire_linkedid(new_snapshot, event_time);
945 }
946 return;
947 }
948
949 if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
950 cel_report_event(new_snapshot, AST_CEL_ANSWER, event_time, NULL, NULL, NULL);
951 return;
952 }
953}
954
956 struct ast_channel_snapshot *old_snapshot,
957 struct ast_channel_snapshot *new_snapshot,
958 const struct timeval *event_time)
959{
960 if (!old_snapshot) {
961 return;
962 }
963
964 ast_assert(!ast_strlen_zero(new_snapshot->peer->linkedid));
965 ast_assert(!ast_strlen_zero(old_snapshot->peer->linkedid));
966
968 && strcmp(old_snapshot->peer->linkedid, new_snapshot->peer->linkedid)) {
969 cel_linkedid_ref(new_snapshot->peer->linkedid);
970 check_retire_linkedid(old_snapshot, event_time);
971 }
972}
973
975 struct ast_channel_snapshot *old_snapshot,
976 struct ast_channel_snapshot *new_snapshot,
977 const struct timeval *event_time)
978{
979 if (old_snapshot && !strcmp(old_snapshot->dialplan->appl, new_snapshot->dialplan->appl)) {
980 return;
981 }
982
983 /* old snapshot has an application, end it */
984 if (old_snapshot && !ast_strlen_zero(old_snapshot->dialplan->appl)) {
985 cel_report_event(old_snapshot, AST_CEL_APP_END, event_time, NULL, NULL, NULL);
986 }
987
988 /* new snapshot has an application, start it */
989 if (!ast_strlen_zero(new_snapshot->dialplan->appl)) {
990 cel_report_event(new_snapshot, AST_CEL_APP_START, event_time, NULL, NULL, NULL);
991 }
992}
993
994/*! \brief Handlers for channel snapshot changes.
995 * \note Order of the handlers matters. Application changes must come before state
996 * changes to ensure that hangup notifications occur after application changes.
997 * Linkedid checking should always come last.
998 */
1003};
1004
1006{
1007 if (!snapshot) {
1008 return 0;
1009 }
1010 return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
1011}
1012
1013static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
1014 struct stasis_message *message)
1015{
1017 size_t i;
1018
1019 if (cel_filter_channel_snapshot(update->old_snapshot) || cel_filter_channel_snapshot(update->new_snapshot)) {
1020 return;
1021 }
1022
1023 for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {
1024 cel_channel_monitors[i](update->old_snapshot, update->new_snapshot, stasis_message_timestamp(message));
1025 }
1026}
1027
1029 struct ast_bridge_snapshot *bridge,
1030 struct ast_channel_snapshot *chan)
1031{
1032 struct ast_str *peer_str = ast_str_create(32);
1033 struct ao2_iterator i;
1034 char *current_chan = NULL;
1035
1036 if (!peer_str) {
1037 return NULL;
1038 }
1039
1040 for (i = ao2_iterator_init(bridge->channels, 0);
1041 (current_chan = ao2_iterator_next(&i));
1042 ao2_cleanup(current_chan)) {
1043 struct ast_channel_snapshot *current_snapshot;
1044
1045 /* Don't add the channel for which this message is being generated */
1046 if (!strcmp(current_chan, chan->base->uniqueid)) {
1047 continue;
1048 }
1049
1050 current_snapshot = ast_channel_snapshot_get_latest(current_chan);
1051 if (!current_snapshot) {
1052 continue;
1053 }
1054
1055 ast_str_append(&peer_str, 0, "%s,", current_snapshot->base->name);
1056 ao2_cleanup(current_snapshot);
1057 }
1059
1060 /* Rip off the trailing comma */
1061 ast_str_truncate(peer_str, -1);
1062
1063 return peer_str;
1064}
1065
1067 void *data, struct stasis_subscription *sub,
1068 struct stasis_message *message)
1069{
1071 struct ast_bridge_snapshot *snapshot = blob->bridge;
1072 struct ast_channel_snapshot *chan_snapshot = blob->channel;
1073 RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1074 RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
1075
1076 if (cel_filter_channel_snapshot(chan_snapshot)) {
1077 return;
1078 }
1079
1080 extra = ast_json_pack("{s: s, s: s}",
1081 "bridge_id", snapshot->uniqueid,
1082 "bridge_technology", snapshot->technology);
1083 if (!extra) {
1084 return;
1085 }
1086
1087 peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
1088 if (!peer_str) {
1089 return;
1090 }
1091
1093 NULL, extra, ast_str_buffer(peer_str));
1094}
1095
1097 void *data, struct stasis_subscription *sub,
1098 struct stasis_message *message)
1099{
1101 struct ast_bridge_snapshot *snapshot = blob->bridge;
1102 struct ast_channel_snapshot *chan_snapshot = blob->channel;
1103 RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1104 RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
1105
1106 if (cel_filter_channel_snapshot(chan_snapshot)) {
1107 return;
1108 }
1109
1110 extra = ast_json_pack("{s: s, s: s}",
1111 "bridge_id", snapshot->uniqueid,
1112 "bridge_technology", snapshot->technology);
1113 if (!extra) {
1114 return;
1115 }
1116
1117 peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
1118 if (!peer_str) {
1119 return;
1120 }
1121
1123 NULL, extra, ast_str_buffer(peer_str));
1124}
1125
1126static void cel_parking_cb(
1127 void *data, struct stasis_subscription *sub,
1128 struct stasis_message *message)
1129{
1130 struct ast_parked_call_payload *parked_payload = stasis_message_data(message);
1131 RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1132 const char *reason = NULL;
1133
1134 switch (parked_payload->event_type) {
1135 case PARKED_CALL:
1136 extra = ast_json_pack("{s: s, s: s}",
1137 "parker_dial_string", parked_payload->parker_dial_string,
1138 "parking_lot", parked_payload->parkinglot);
1139 if (extra) {
1141 NULL, extra, NULL);
1142 }
1143 return;
1145 reason = "ParkedCallTimeOut";
1146 break;
1147 case PARKED_CALL_GIVEUP:
1148 reason = "ParkedCallGiveUp";
1149 break;
1151 reason = "ParkedCallUnparked";
1152 break;
1153 case PARKED_CALL_FAILED:
1154 reason = "ParkedCallFailed";
1155 break;
1156 case PARKED_CALL_SWAP:
1157 reason = "ParkedCallSwap";
1158 break;
1159 }
1160
1161 if (parked_payload->retriever) {
1162 extra = ast_json_pack("{s: s, s: s}",
1163 "reason", reason ?: "",
1164 "retriever", parked_payload->retriever->base->name);
1165 } else {
1166 extra = ast_json_pack("{s: s}", "reason", reason ?: "");
1167 }
1168
1169 if (extra) {
1171 NULL, extra, NULL);
1172 }
1173}
1174
1175static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_channel_snapshot *snapshot)
1176{
1177 struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
1178 const char *dialstatus_string = get_blob_variable(blob, "dialstatus");
1179 struct cel_dialstatus *dialstatus;
1180 size_t dialstatus_string_len;
1181
1182 if (!dial_statuses || ast_strlen_zero(dialstatus_string)) {
1183 ao2_cleanup(dial_statuses);
1184 return;
1185 }
1186
1187 dialstatus = ao2_find(dial_statuses, snapshot->base->uniqueid, OBJ_SEARCH_KEY);
1188 if (dialstatus) {
1189 if (!strcasecmp(dialstatus_string, "ANSWER") && strcasecmp(dialstatus->dialstatus, "ANSWER")) {
1190 /* In the case of an answer after we already have a dial status we give
1191 * priority to the answer since the call was, well, answered. In the case of
1192 * failure dial status results we simply let the first failure be the status.
1193 */
1194 ao2_unlink(dial_statuses, dialstatus);
1195 ao2_ref(dialstatus, -1);
1196 } else {
1197 ao2_ref(dialstatus, -1);
1198 ao2_ref(dial_statuses, -1);
1199 return;
1200 }
1201 }
1202
1203 dialstatus_string_len = strlen(dialstatus_string) + 1;
1204 dialstatus = ao2_alloc_options(sizeof(*dialstatus) + dialstatus_string_len, NULL,
1206 if (!dialstatus) {
1207 ao2_ref(dial_statuses, -1);
1208 return;
1209 }
1210
1211 ast_copy_string(dialstatus->uniqueid, snapshot->base->uniqueid, sizeof(dialstatus->uniqueid));
1212 ast_copy_string(dialstatus->dialstatus, dialstatus_string, dialstatus_string_len);
1213
1214 ao2_link(dial_statuses, dialstatus);
1215 ao2_ref(dialstatus, -1);
1216 ao2_ref(dial_statuses, -1);
1217}
1218
1220{
1221 const char *dialstatus = get_blob_variable(blob, "dialstatus");
1222 int res = 0;
1223
1225 res = 0;
1226 } else if (!strcasecmp(dialstatus, "CHANUNAVAIL")) {
1227 res = 1;
1228 } else if (!strcasecmp(dialstatus, "CONGESTION")) {
1229 res = 1;
1230 } else if (!strcasecmp(dialstatus, "NOANSWER")) {
1231 res = 1;
1232 } else if (!strcasecmp(dialstatus, "BUSY")) {
1233 res = 1;
1234 } else if (!strcasecmp(dialstatus, "ANSWER")) {
1235 res = 1;
1236 } else if (!strcasecmp(dialstatus, "CANCEL")) {
1237 res = 1;
1238 } else if (!strcasecmp(dialstatus, "DONTCALL")) {
1239 res = 1;
1240 } else if (!strcasecmp(dialstatus, "TORTURE")) {
1241 res = 1;
1242 } else if (!strcasecmp(dialstatus, "INVALIDARGS")) {
1243 res = 1;
1244 }
1245 return res;
1246}
1247
1248static void cel_dial_cb(void *data, struct stasis_subscription *sub,
1249 struct stasis_message *message)
1250{
1252 struct ast_channel_snapshot *snapshot;
1253
1254 snapshot = ast_multi_channel_blob_get_channel(blob, "caller");
1255 if (!snapshot || cel_filter_channel_snapshot(snapshot)) {
1256 return;
1257 }
1258
1259 if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
1260 struct ast_json *extra;
1261
1262 extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
1263 if (extra) {
1265 NULL, extra, NULL);
1266 ast_json_unref(extra);
1267 }
1268 }
1269
1270 if (is_valid_dialstatus(blob)) {
1271 save_dialstatus(blob, snapshot);
1272 }
1273}
1274
1275static void cel_generic_cb(
1276 void *data, struct stasis_subscription *sub,
1277 struct stasis_message *message)
1278{
1280 int event_type = ast_json_integer_get(ast_json_object_get(obj->blob, "event_type"));
1281 struct ast_json *event_details = ast_json_object_get(obj->blob, "event_details");
1282
1283 switch (event_type) {
1285 {
1286 const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
1287 struct ast_json *extra = ast_json_object_get(event_details, "extra");
1289 event, extra, NULL);
1290 break;
1291 }
1292 default:
1293 ast_log(LOG_ERROR, "Unhandled %s event blob\n", ast_cel_get_type_name(event_type));
1294 break;
1295 }
1296}
1297
1299 void *data, struct stasis_subscription *sub,
1300 struct stasis_message *message)
1301{
1303 struct ast_channel_snapshot *chan_snapshot = transfer_msg->transferer;
1304 struct ast_bridge_snapshot *bridge_snapshot = transfer_msg->bridge;
1305 struct ast_json *extra;
1306
1307 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
1308 return;
1309 }
1310
1311 extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
1312 "extension", transfer_msg->exten,
1313 "context", transfer_msg->context,
1314 "bridge_id", bridge_snapshot->uniqueid,
1315 "transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->base->name : "N/A",
1316 "transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->base->uniqueid : "N/A");
1317 if (extra) {
1319 NULL, extra, NULL);
1320 ast_json_unref(extra);
1321 }
1322}
1323
1325 void *data, struct stasis_subscription *sub,
1326 struct stasis_message *message)
1327{
1329 struct ast_json *extra = NULL;
1330 struct ast_bridge_snapshot *bridge1, *bridge2;
1331 struct ast_channel_snapshot *channel1, *channel2;
1332
1333 /* Make sure bridge1 is always non-NULL */
1334 if (!xfer->to_transferee.bridge_snapshot) {
1335 bridge1 = xfer->to_transfer_target.bridge_snapshot;
1336 bridge2 = xfer->to_transferee.bridge_snapshot;
1337 channel1 = xfer->to_transfer_target.channel_snapshot;
1338 channel2 = xfer->to_transferee.channel_snapshot;
1339 } else {
1340 bridge1 = xfer->to_transferee.bridge_snapshot;
1341 bridge2 = xfer->to_transfer_target.bridge_snapshot;
1342 channel1 = xfer->to_transferee.channel_snapshot;
1343 channel2 = xfer->to_transfer_target.channel_snapshot;
1344 }
1345
1346 switch (xfer->dest_type) {
1348 return;
1349 /* handle these three the same */
1353 extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
1354 "bridge1_id", bridge1->uniqueid,
1355 "channel2_name", channel2->base->name,
1356 "channel2_uniqueid", channel2->base->uniqueid,
1357 "bridge2_id", bridge2->uniqueid,
1358 "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
1359 "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
1360 "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
1361 "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
1362 if (!extra) {
1363 return;
1364 }
1365 break;
1368 extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
1369 "bridge1_id", bridge1->uniqueid,
1370 "channel2_name", channel2->base->name,
1371 "channel2_uniqueid", channel2->base->uniqueid,
1372 "app", xfer->dest.app,
1373 "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
1374 "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
1375 "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
1376 "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
1377 if (!extra) {
1378 return;
1379 }
1380 break;
1381 }
1383 NULL, extra, NULL);
1384 ast_json_unref(extra);
1385}
1386
1387static void cel_pickup_cb(
1388 void *data, struct stasis_subscription *sub,
1389 struct stasis_message *message)
1390{
1392 struct ast_channel_snapshot *channel = ast_multi_channel_blob_get_channel(obj, "channel");
1393 struct ast_channel_snapshot *target = ast_multi_channel_blob_get_channel(obj, "target");
1394 struct ast_json *extra;
1395
1396 if (!channel || !target) {
1397 return;
1398 }
1399
1400 extra = ast_json_pack("{s: s, s: s}",
1401 "pickup_channel", channel->base->name,
1402 "pickup_channel_uniqueid", channel->base->uniqueid);
1403 if (!extra) {
1404 return;
1405 }
1406
1408 ast_json_unref(extra);
1409}
1410
1411
1413 void *data, struct stasis_subscription *sub,
1414 struct stasis_message *message,
1415 enum ast_cel_event_type event_type)
1416{
1418 struct ast_channel_snapshot *localone = ast_multi_channel_blob_get_channel(obj, "1");
1419 struct ast_channel_snapshot *localtwo = ast_multi_channel_blob_get_channel(obj, "2");
1420 struct ast_json *extra;
1421
1422 if (!localone || !localtwo) {
1423 return;
1424 }
1425
1426 extra = ast_json_pack("{s: s, s: s}",
1427 "local_two", localtwo->base->name,
1428 "local_two_uniqueid", localtwo->base->uniqueid);
1429 if (!extra) {
1430 return;
1431 }
1432
1433 cel_report_event(localone, event_type, stasis_message_timestamp(message), NULL, extra, NULL);
1434 ast_json_unref(extra);
1435}
1436
1438 void *data, struct stasis_subscription *sub,
1439 struct stasis_message *message)
1440{
1441 /* The AST_CEL_LOCAL_OPTIMIZE event has always been triggered by the end of optimization.
1442 This can either be used as an indication that the call was locally optimized, or as
1443 the END event in combination with the subsequently added BEGIN event. */
1445}
1446
1448 void *data, struct stasis_subscription *sub,
1449 struct stasis_message *message)
1450{
1452}
1453
1454static void destroy_routes(void)
1455{
1458}
1459
1460static void destroy_subscriptions(void)
1461{
1465 cel_topic = NULL;
1466
1471}
1472
1473static int unload_module(void)
1474{
1478
1480 aco_info_destroy(&cel_cfg_info);
1481 ao2_global_obj_release(cel_configs);
1482 ao2_global_obj_release(cel_dialstatus_store);
1483 ao2_global_obj_release(cel_linkedids);
1484 ao2_global_obj_release(cel_backends);
1485
1486 return 0;
1487}
1488
1489/*!
1490 * \brief Create the Stasis subscriptions for CEL
1491 */
1492static int create_subscriptions(void)
1493{
1494 cel_aggregation_topic = stasis_topic_create("cel:aggregator");
1495 if (!cel_aggregation_topic) {
1496 return -1;
1497 }
1498
1499 cel_topic = stasis_topic_create("cel:misc");
1500 if (!cel_topic) {
1501 return -1;
1502 }
1503
1507 if (!cel_channel_forwarder) {
1508 return -1;
1509 }
1510
1514 if (!cel_bridge_forwarder) {
1515 return -1;
1516 }
1517
1521 if (!cel_parking_forwarder) {
1522 return -1;
1523 }
1524
1526 ast_cel_topic(),
1528 if (!cel_cel_forwarder) {
1529 return -1;
1530 }
1531
1532 return 0;
1533}
1534
1535/*!
1536 * \brief Create the Stasis message router and routes for CEL
1537 */
1538static int create_routes(void)
1539{
1540 int ret = 0;
1541
1543 if (!cel_state_router) {
1544 return -1;
1545 }
1548
1552 NULL);
1553
1557 NULL);
1558
1562 NULL);
1563
1567 NULL);
1568
1572 NULL);
1573
1577 NULL);
1578
1582 NULL);
1583
1587 NULL);
1588
1592 NULL);
1593
1597 NULL);
1598
1602 NULL);
1603
1604 if (ret) {
1605 ast_log(AST_LOG_ERROR, "Failed to register for Stasis messages\n");
1606 }
1607
1608 return ret;
1609}
1610
1613
1614static int load_module(void)
1615{
1616 struct ao2_container *container;
1617
1619 NUM_APP_BUCKETS, cel_linkedid_hash_fn, NULL, cel_linkedid_cmp_fn);
1622 if (!container) {
1624 }
1625
1627 NUM_DIALSTATUS_BUCKETS, cel_dialstatus_hash_fn, NULL, cel_dialstatus_cmp_fn);
1628 ao2_global_obj_replace_unref(cel_dialstatus_store, container);
1630 if (!container) {
1632 }
1633
1636 }
1637
1640 }
1641
1643 cel_backend_hash_fn, NULL, cel_backend_cmp_fn);
1646 if (!container) {
1648 }
1649
1650 if (aco_info_init(&cel_cfg_info)) {
1652 }
1653
1654 aco_option_register(&cel_cfg_info, "enable", ACO_EXACT, general_options, "no", OPT_BOOL_T, 1, FLDSET(struct ast_cel_general_config, enable));
1655 aco_option_register(&cel_cfg_info, "dateformat", ACO_EXACT, general_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_cel_general_config, date_format));
1656 aco_option_register_custom(&cel_cfg_info, "apps", ACO_EXACT, general_options, "", apps_handler, 0);
1657 aco_option_register_custom(&cel_cfg_info, "events", ACO_EXACT, general_options, "", events_handler, 0);
1658
1659 if (aco_process_config(&cel_cfg_info, 0)) {
1660 struct cel_config *cel_cfg = cel_config_alloc();
1661
1662 if (!cel_cfg) {
1664 }
1665
1666 /* We couldn't process the configuration so create a default config. */
1667 if (!aco_set_defaults(&general_option, "general", cel_cfg->general)) {
1668 ast_log(LOG_NOTICE, "Failed to process CEL configuration; using defaults\n");
1669 ao2_global_obj_replace_unref(cel_configs, cel_cfg);
1670 }
1671 ao2_ref(cel_cfg, -1);
1672 }
1673
1674 if (create_subscriptions()) {
1676 }
1677
1680 }
1681
1683}
1684
1685static int reload_module(void)
1686{
1687 unsigned int was_enabled = ast_cel_check_enabled();
1688 unsigned int is_enabled;
1689
1690 if (aco_process_config(&cel_cfg_info, 1) == ACO_PROCESS_ERROR) {
1691 return -1;
1692 }
1693
1695
1696 if (!was_enabled && is_enabled) {
1697 if (create_routes()) {
1698 return -1;
1699 }
1700 } else if (was_enabled && !is_enabled) {
1702 }
1703
1704 ast_verb(3, "CEL logging %sabled.\n", is_enabled ? "en" : "dis");
1705
1706 return 0;
1707}
1708
1710 const char *event,
1711 const char *extra)
1712{
1713 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1714
1715 blob = ast_json_pack("{s: s, s: {s: s}}",
1716 "event", event,
1717 "extra", "extra", S_OR(extra, ""));
1718 if (!blob) {
1719 return;
1720 }
1722}
1723
1725 enum ast_cel_event_type event_type,
1726 struct ast_json *blob)
1727{
1728 struct ast_json *cel_blob;
1729 struct stasis_message *message;
1730
1731 cel_blob = ast_json_pack("{s: i, s: o}",
1732 "event_type", event_type,
1733 "event_details", ast_json_ref(blob));
1734
1736 if (message) {
1738 }
1740 ast_json_unref(cel_blob);
1741}
1742
1744{
1745 return cel_topic;
1746}
1747
1749{
1750 RAII_VAR(struct cel_config *, mod_cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
1751
1752 if (!mod_cfg || !mod_cfg->general) {
1753 return NULL;
1754 }
1755
1756 ao2_ref(mod_cfg->general, +1);
1757 return mod_cfg->general;
1758}
1759
1761{
1762 int was_enabled;
1763 int is_enabled;
1764 struct ast_cel_general_config *cleanup_config;
1765 struct cel_config *mod_cfg = ao2_global_obj_ref(cel_configs);
1766
1767 if (mod_cfg) {
1768 was_enabled = ast_cel_check_enabled();
1769
1770 cleanup_config = mod_cfg->general;
1772 mod_cfg->general = config;
1773 ao2_cleanup(cleanup_config);
1774
1776 if (!was_enabled && is_enabled) {
1777 create_routes();
1778 } else if (was_enabled && !is_enabled) {
1780 }
1781
1782 ao2_ref(mod_cfg, -1);
1783 }
1784}
1785
1787{
1788 struct ao2_container *backends = ao2_global_obj_ref(cel_backends);
1789
1790 if (backends) {
1792 ao2_ref(backends, -1);
1793 }
1794
1795 return 0;
1796}
1797
1798int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
1799{
1801 struct cel_backend *backend;
1802
1803 if (!backends || ast_strlen_zero(name) || !backend_callback) {
1804 return -1;
1805 }
1806
1807 /* The backend object is immutable so it doesn't need a lock of its own. */
1808 backend = ao2_alloc_options(sizeof(*backend) + 1 + strlen(name), NULL,
1810 if (!backend) {
1811 return -1;
1812 }
1813 strcpy(backend->name, name);/* Safe */
1814 backend->callback = backend_callback;
1815
1816 ao2_link(backends, backend);
1817 ao2_ref(backend, -1);
1818 return 0;
1819}
1820
1822 .support_level = AST_MODULE_SUPPORT_CORE,
1823 .load = load_module,
1824 .unload = unload_module,
1826 .load_pri = AST_MODPRI_CORE,
1827 .requires = "extconfig",
static const char app[]
Definition: app_adsiprog.c:56
static const struct adsi_event events[]
Definition: app_adsiprog.c:88
#define var
Definition: ast_expr2f.c:605
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
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_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:1454
void ast_cel_publish_user_event(struct ast_channel *chan, const char *event, const char *extra)
Publish a CEL user event.
Definition: cel.c:1709
static struct aco_type ignore_option
Definition: cel.c:272
void ast_cel_set_config(struct ast_cel_general_config *config)
Set the current CEL configuration.
Definition: cel.c:1760
static int cel_linkedid_ref(const char *linkedid)
Definition: cel.c:799
static void cel_general_config_dtor(void *obj)
Destructor for cel_config.
Definition: cel.c:196
static const char * ignore_categories[]
Definition: cel.c:266
#define BACKEND_BUCKETS
Definition: cel.c:157
static struct ast_cli_entry cli_status
Definition: cel.c:433
static struct stasis_forward * cel_cel_forwarder
Definition: cel.c:148
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:587
static int ast_cel_track_event(enum ast_cel_event_type et)
Definition: cel.c:449
#define CEL_MAX_EVENT_IDS
Maximum possible CEL event IDs.
Definition: cel.c:166
static int create_subscriptions(void)
Create the Stasis subscriptions for CEL.
Definition: cel.c:1492
static void cel_local_optimization_end_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1437
int ast_cel_backend_unregister(const char *name)
Unregister a CEL backend.
Definition: cel.c:1786
static const char *const cel_event_types[CEL_MAX_EVENT_IDS]
Map of ast_cel_event_type to strings.
Definition: cel.c:321
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:882
STASIS_MESSAGE_TYPE_DEFN(cel_generic_type)
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:534
static int create_routes(void)
Create the Stasis message router and routes for CEL.
Definition: cel.c:1538
static int is_valid_dialstatus(struct ast_multi_channel_blob *blob)
Definition: cel.c:1219
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:257
enum ast_cel_event_type ast_cel_str_to_event_type(const char *name)
Get the event type from a string.
Definition: cel.c:435
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:1724
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:955
static void cel_bridge_leave_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1096
static void cel_dial_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1248
static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1013
static AO2_GLOBAL_OBJ_STATIC(cel_backends)
static int events_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition: cel.c:460
void * ast_cel_general_config_alloc(void)
Allocate a CEL configuration object.
Definition: cel.c:204
unsigned int ast_cel_check_enabled(void)
Hashing function for cel_backend.
Definition: cel.c:360
#define NUM_DIALSTATUS_BUCKETS
Number of buckets for the dialstatus container.
Definition: cel.c:176
static struct aco_file cel_conf
The config file to be processed for the module.
Definition: cel.c:280
static int reload_module(void)
Definition: cel.c:1685
static void check_retire_linkedid(struct ast_channel_snapshot *snapshot, const struct timeval *event_time)
Definition: cel.c:632
static int cel_filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
Definition: cel.c:1005
static void cel_pickup_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1387
static void cel_blind_transfer_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1298
static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_channel_snapshot *snapshot)
Definition: cel.c:1175
struct stasis_topic * ast_cel_topic(void)
Get the CEL topic.
Definition: cel.c:1743
static struct aco_type * general_options[]
Definition: cel.c:316
static void cel_config_dtor(void *obj)
Destructor for cel_config.
Definition: cel.c:233
static void cel_attended_transfer_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1324
static int cel_track_app(const char *const_app)
Definition: cel.c:513
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:678
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:837
static const char * get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
Definition: cel.c:899
static int cel_pre_apply_config(void)
Definition: cel.c:292
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:915
static struct stasis_forward * cel_channel_forwarder
Definition: cel.c:139
cel_channel_snapshot_monitor cel_channel_monitors[]
Handlers for channel snapshot changes.
Definition: cel.c:999
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:370
static int load_module(void)
Definition: cel.c:1614
CONFIG_INFO_CORE("cel", cel_cfg_info, cel_configs, cel_config_alloc,.files=ACO_FILES(&cel_conf),.pre_apply_config=cel_pre_apply_config,)
static int cel_backend_send_cb(void *obj, void *arg, int flags)
Definition: cel.c:579
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:974
static int apps_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition: cel.c:489
static struct ast_str * cel_generate_peer_str(struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *chan)
Definition: cel.c:1028
#define NUM_APP_BUCKETS
Number of buckets for the appset container.
Definition: cel.c:171
static const struct ast_datastore_info fabricated_channel_datastore
Definition: cel.c:673
static void cel_generic_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1275
static struct stasis_forward * cel_bridge_forwarder
Definition: cel.c:142
static void cel_parking_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1126
static struct stasis_message_router * cel_state_router
Definition: cel.c:130
static struct stasis_topic * cel_topic
Definition: cel.c:133
static int unload_module(void)
Definition: cel.c:1473
static struct cel_dialstatus * get_dialstatus(const char *uniqueid)
Definition: cel.c:887
struct ast_cel_general_config * ast_cel_get_config(void)
Obtain the current CEL configuration.
Definition: cel.c:1748
static void * cel_config_alloc(void)
Definition: cel.c:240
int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
Register a CEL backend.
Definition: cel.c:1798
const char * ast_cel_get_type_name(enum ast_cel_event_type type)
Get the name of a CEL event type.
Definition: cel.c:508
static void destroy_subscriptions(void)
Definition: cel.c:1460
static struct stasis_forward * cel_parking_forwarder
Definition: cel.c:145
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:544
static void cel_local_optimization_begin_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1447
static void cel_bridge_enter_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1066
static struct stasis_topic * cel_aggregation_topic
Definition: cel.c:136
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:1412
Call Event Logging API.
ast_cel_event_type
CEL event types.
Definition: cel.h:41
@ AST_CEL_CHANNEL_END
channel end
Definition: cel.h:47
@ AST_CEL_APP_END
an app ends
Definition: cel.h:55
@ AST_CEL_ANSWER
A ringing phone is answered.
Definition: cel.h:51
@ AST_CEL_PARK_START
a channel is parked
Definition: cel.h:61
@ AST_CEL_LINKEDID_END
the last channel with the given linkedid is retired
Definition: cel.h:71
@ AST_CEL_INVALID_VALUE
Definition: cel.h:42
@ AST_CEL_BRIDGE_EXIT
channel exits a bridge
Definition: cel.h:59
@ AST_CEL_FORWARD
this call was forwarded somewhere else
Definition: cel.h:75
@ AST_CEL_HANGUP
hangup terminates connection
Definition: cel.h:49
@ AST_CEL_USER_DEFINED
a user-defined event, the event name field should be set
Definition: cel.h:69
@ AST_CEL_PICKUP
a directed pickup was performed on this channel
Definition: cel.h:73
@ AST_CEL_APP_START
an app starts
Definition: cel.h:53
@ AST_CEL_LOCAL_OPTIMIZE_BEGIN
A local channel optimization has begun.
Definition: cel.h:79
@ AST_CEL_ALL
Definition: cel.h:43
@ AST_CEL_PARK_END
channel out of the park
Definition: cel.h:63
@ AST_CEL_CHANNEL_START
channel birth
Definition: cel.h:45
@ AST_CEL_ATTENDEDTRANSFER
a transfer occurs
Definition: cel.h:67
@ AST_CEL_BRIDGE_ENTER
channel enters a bridge
Definition: cel.h:57
@ AST_CEL_BLINDTRANSFER
a transfer occurs
Definition: cel.h:65
@ AST_CEL_LOCAL_OPTIMIZE
A local channel optimization occurred, this marks the end.
Definition: cel.h:77
void(* ast_cel_backend_cb)(struct ast_event *event)
CEL backend callback.
Definition: cel.h:311
#define AST_CEL_EVENT_RECORD_VERSION
struct ABI version
Definition: cel.h:143
static const char type[]
Definition: chan_ooh323.c:109
static const char config[]
Definition: chan_ooh323.c:111
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:2414
struct varshead * ast_channel_varshead(struct ast_channel *chan)
void ast_channel_data_set(struct ast_channel *chan, const char *value)
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:991
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:3006
@ AST_FLAG_DEAD
Definition: channel.h:1065
#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
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
@ AST_STATE_UP
Definition: channelstate.h:42
#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:2439
#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
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
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.
Definition: linkedlists.h:711
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:203
static int reload(void)
struct stasis_forward * sub
Definition: res_corosync.c:240
struct ao2_container * container
Definition: res_fax.c:531
#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:1575
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:644
#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.
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:1605
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1538
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.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
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
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
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
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:68
Message representing attended transfer.
enum ast_attended_transfer_dest_type dest_type
union ast_attended_transfer_message::@286 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:138
const char * caller_id_dnid
Definition: cel.h:157
const char * application_data
Definition: cel.h:162
const char * account_code
Definition: cel.h:163
const char * caller_id_rdnis
Definition: cel.h:156
const char * extra
Definition: cel.h:171
const char * extension
Definition: cel.h:158
const char * caller_id_num
Definition: cel.h:154
const char * channel_name
Definition: cel.h:160
const char * linked_id
Definition: cel.h:166
const char * peer_account
Definition: cel.h:164
const char * peer
Definition: cel.h:170
enum ast_cel_event_type event_type
Definition: cel.h:149
const char * unique_id
Definition: cel.h:165
const char * user_defined_name
Definition: cel.h:152
const char * context
Definition: cel.h:159
const char * application_name
Definition: cel.h:161
struct timeval event_time
Definition: cel.h:150
uint32_t version
struct ABI version
Definition: cel.h:148
const char * tenant_id
Definition: cel.h:167
const char * user_field
Definition: cel.h:169
const char * caller_id_ani
Definition: cel.h:155
const char * caller_id_name
Definition: cel.h:153
const char * event_name
Definition: cel.h:151
A structure to hold CEL global configuration options.
Definition: cel.h:224
int64_t events
Definition: cel.h:229
struct ao2_container * apps
Definition: cel.h:233
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
struct ast_party_dialed::@210 number
Dialed/Called number.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
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:121
ast_cel_backend_cb callback
Definition: cel.c:344
char name[0]
Definition: cel.c:345
A container that holds all config-related information.
Definition: cel_custom.c:52
struct ast_cel_general_config * general
Definition: cel.c:226
char dialstatus[0]
Definition: cel.c:192
char uniqueid[AST_MAX_UNIQUEID]
Definition: cel.c:190
unsigned int count
Definition: cel.c:180
char id[0]
Definition: cel.c:182
Definition: astman.c:222
Forwarding information.
Definition: stasis.c:1558
An API for managing task processing threads that can be shared across modules.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
Definition: taskprocessor.h:64
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: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
#define ast_assert(a)
Definition: utils.h:739
#define ARRAY_LEN(a)
Definition: utils.h:666