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