Asterisk - The Open Source Telephony Project GIT-master-0deac78
cel.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2007 - 2009, Digium, Inc.
5 *
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
11 *
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
15 */
16
17/*!
18 * \file
19 *
20 * \brief Channel Event Logging API
21 *
22 * \author Steve Murphy <murf@digium.com>
23 * \author Russell Bryant <russell@digium.com>
24 */
25
26/*! \li \ref cel.c uses the configuration file \ref cel.conf
27 * \addtogroup configuration_file Configuration Files
28 */
29
30/*!
31 * \page cel.conf cel.conf
32 * \verbinclude cel.conf.sample
33 */
34
35/*** MODULEINFO
36 <support_level>core</support_level>
37 ***/
38
39#include "asterisk.h"
40
41#include "asterisk/module.h"
42
43#include "asterisk/channel.h"
44#include "asterisk/pbx.h"
45#include "asterisk/cel.h"
46#include "asterisk/logger.h"
48#include "asterisk/utils.h"
49#include "asterisk/config.h"
51#include "asterisk/cli.h"
52#include "asterisk/astobj2.h"
56#include "asterisk/bridge.h"
57#include "asterisk/parking.h"
58#include "asterisk/pickup.h"
59#include "asterisk/core_local.h"
61
62/*** DOCUMENTATION
63 <configInfo name="cel" language="en_US">
64 <configFile name="cel.conf">
65 <configObject name="general">
66 <since>
67 <version>12.0.0</version>
68 </since>
69 <synopsis>Options that apply globally to Channel Event Logging (CEL)</synopsis>
70 <configOption name="enable">
71 <since>
72 <version>12.0.0</version>
73 </since>
74 <synopsis>Determines whether CEL is enabled</synopsis>
75 </configOption>
76 <configOption name="dateformat">
77 <since>
78 <version>12.0.0</version>
79 </since>
80 <synopsis>The format to be used for dates when logging</synopsis>
81 </configOption>
82 <configOption name="apps">
83 <since>
84 <version>12.0.0</version>
85 </since>
86 <synopsis>List of apps for CEL to track</synopsis>
87 <description><para>A case-insensitive, comma-separated list of applications
88 to track when one or both of APP_START and APP_END events are flagged for
89 tracking</para></description>
90 </configOption>
91 <configOption name="events">
92 <since>
93 <version>12.0.0</version>
94 </since>
95 <synopsis>List of events for CEL to track</synopsis>
96 <description><para>A case-sensitive, comma-separated list of event names
97 to track. These event names do not include the leading <literal>AST_CEL</literal>.
98 </para>
99 <enumlist>
100 <enum name="ALL">
101 <para>Special value which tracks all events.</para>
102 </enum>
103 <enum name="CHAN_START"/>
104 <enum name="CHAN_END"/>
105 <enum name="ANSWER"/>
106 <enum name="HANGUP"/>
107 <enum name="APP_START"/>
108 <enum name="APP_END"/>
109 <enum name="PARK_START"/>
110 <enum name="PARK_END"/>
111 <enum name="USER_DEFINED"/>
112 <enum name="BRIDGE_ENTER"/>
113 <enum name="BRIDGE_EXIT"/>
114 <enum name="BLINDTRANSFER"/>
115 <enum name="ATTENDEDTRANSFER"/>
116 <enum name="PICKUP"/>
117 <enum name="FORWARD"/>
118 <enum name="LINKEDID_END"/>
119 <enum name="LOCAL_OPTIMIZE"/>
120 <enum name="LOCAL_OPTIMIZE_BEGIN"/>
121 <enum name="STREAM_BEGIN"/>
122 <enum name="STREAM_END"/>
123 <enum name="DTMF"/>
124 </enumlist>
125 </description>
126 </configOption>
127 </configObject>
128 </configFile>
129 </configInfo>
130 ***/
131
132/*! Message router for state that CEL needs to know about */
134
135/*! Topic for CEL-specific messages */
136static struct stasis_topic *cel_topic;
137
138/*! Aggregation topic for all topics CEL needs to know about */
140
141/*! Subscription for forwarding the channel caching topic */
143
144/*! Subscription for forwarding the channel caching topic */
146
147/*! Subscription for forwarding the parking topic */
149
150/*! Subscription for forwarding the CEL-specific topic */
152
155
156/*! Container for CEL backend information */
157static AO2_GLOBAL_OBJ_STATIC(cel_backends);
158
159/*! The number of buckets into which backend names will be hashed */
160#define BACKEND_BUCKETS 13
161
162/*! Container for dial end multichannel blobs for holding on to dial statuses */
163static AO2_GLOBAL_OBJ_STATIC(cel_dialstatus_store);
164
165/*!
166 * \brief Maximum possible CEL event IDs
167 * \note This limit is currently imposed by the eventset definition
168 */
169#define CEL_MAX_EVENT_IDS 64
170
171/*!
172 * \brief Number of buckets for the appset container
173 */
174#define NUM_APP_BUCKETS 97
175
176/*!
177 * \brief Number of buckets for the dialstatus container
178 */
179#define NUM_DIALSTATUS_BUCKETS 251
180
182 /*! Number of channels with this linkedid. */
183 unsigned int count;
184 /*! Linkedid stored at end of struct. */
185 char id[0];
186};
187
188/*! Container of channel references to a linkedid for CEL purposes. */
189static AO2_GLOBAL_OBJ_STATIC(cel_linkedids);
190
192 /*! Uniqueid of the channel */
194 /*! The dial status */
195 char dialstatus[0];
196};
197
198/*! \brief Destructor for cel_config */
199static void cel_general_config_dtor(void *obj)
200{
201 struct ast_cel_general_config *cfg = obj;
203 ao2_cleanup(cfg->apps);
204 cfg->apps = NULL;
205}
206
208{
210
211 if (!(cfg = ao2_alloc(sizeof(*cfg), cel_general_config_dtor))) {
212 return NULL;
213 }
214
215 if (ast_string_field_init(cfg, 64)) {
216 return NULL;
217 }
218
219 if (!(cfg->apps = ast_str_container_alloc(NUM_APP_BUCKETS))) {
220 return NULL;
221 }
222
223 ao2_ref(cfg, +1);
224 return cfg;
225}
226
227/*! \brief A container that holds all config-related information */
228struct cel_config {
230};
231
232
233static AO2_GLOBAL_OBJ_STATIC(cel_configs);
234
235/*! \brief Destructor for cel_config */
236static void cel_config_dtor(void *obj)
237{
238 struct cel_config *cfg = obj;
239 ao2_cleanup(cfg->general);
240 cfg->general = NULL;
241}
242
243static void *cel_config_alloc(void)
244{
245 RAII_VAR(struct cel_config *, cfg, NULL, ao2_cleanup);
246
247 if (!(cfg = ao2_alloc(sizeof(*cfg), cel_config_dtor))) {
248 return NULL;
249 }
250
251 if (!(cfg->general = ast_cel_general_config_alloc())) {
252 return NULL;
253 }
254
255 ao2_ref(cfg, +1);
256 return cfg;
257}
258
259/*! \brief An aco_type structure to link the "general" category to the ast_cel_general_config type */
260static struct aco_type general_option = {
261 .type = ACO_GLOBAL,
262 .name = "general",
263 .item_offset = offsetof(struct cel_config, general),
264 .category_match = ACO_WHITELIST_EXACT,
265 .category = "general",
266};
267
268/*! Config sections used by existing modules. Do not add to this list. */
269static const char *ignore_categories[] = {
270 "manager",
271 "radius",
272 NULL,
273};
274
275static struct aco_type ignore_option = {
276 .type = ACO_IGNORE,
277 .name = "modules",
278 .category = (const char*)ignore_categories,
280};
281
282/*! \brief The config file to be processed for the module. */
283static struct aco_file cel_conf = {
284 .filename = "cel.conf", /*!< The name of the config file */
285 .types = ACO_TYPES(&general_option, &ignore_option), /*!< The mapping object types to be processed */
286};
287
288static int cel_pre_apply_config(void);
289
290CONFIG_INFO_CORE("cel", cel_cfg_info, cel_configs, cel_config_alloc,
291 .files = ACO_FILES(&cel_conf),
292 .pre_apply_config = cel_pre_apply_config,
293);
294
295static int cel_pre_apply_config(void)
296{
297 struct cel_config *cfg = aco_pending_config(&cel_cfg_info);
298
299 if (!cfg->general) {
300 return -1;
301 }
302
303 if (!ao2_container_count(cfg->general->apps)) {
304 return 0;
305 }
306
307 if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_START)) {
308 return 0;
309 }
310
311 if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_END)) {
312 return 0;
313 }
314
315 ast_log(LOG_ERROR, "Applications are listed to be tracked, but APP events are not tracked\n");
316 return -1;
317}
318
320
321/*!
322 * \brief Map of ast_cel_event_type to strings
323 */
324static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
325 [AST_CEL_ALL] = "ALL",
326 [AST_CEL_CHANNEL_START] = "CHAN_START",
327 [AST_CEL_CHANNEL_END] = "CHAN_END",
328 [AST_CEL_ANSWER] = "ANSWER",
329 [AST_CEL_HANGUP] = "HANGUP",
330 [AST_CEL_APP_START] = "APP_START",
331 [AST_CEL_APP_END] = "APP_END",
332 [AST_CEL_PARK_START] = "PARK_START",
333 [AST_CEL_PARK_END] = "PARK_END",
334 [AST_CEL_USER_DEFINED] = "USER_DEFINED",
335 [AST_CEL_BRIDGE_ENTER] = "BRIDGE_ENTER",
336 [AST_CEL_BRIDGE_EXIT] = "BRIDGE_EXIT",
337 [AST_CEL_BLINDTRANSFER] = "BLINDTRANSFER",
338 [AST_CEL_ATTENDEDTRANSFER] = "ATTENDEDTRANSFER",
339 [AST_CEL_PICKUP] = "PICKUP",
340 [AST_CEL_FORWARD] = "FORWARD",
341 [AST_CEL_LINKEDID_END] = "LINKEDID_END",
342 [AST_CEL_LOCAL_OPTIMIZE] = "LOCAL_OPTIMIZE",
343 [AST_CEL_LOCAL_OPTIMIZE_BEGIN] = "LOCAL_OPTIMIZE_BEGIN",
344 [AST_CEL_STREAM_BEGIN] = "STREAM_BEGIN",
345 [AST_CEL_STREAM_END] = "STREAM_END",
346 [AST_CEL_DTMF] = "DTMF",
347};
348
350 ast_cel_backend_cb callback; /*!< Callback for this backend */
351 char name[0]; /*!< Name of this backend */
352};
353
354/*! \brief Hashing function for cel_backend */
356
357/*! \brief Comparator function for cel_backend */
359
360/*! \brief Hashing function for dialstatus container */
362
363/*! \brief Comparator function for dialstatus container */
365
366unsigned int ast_cel_check_enabled(void)
367{
368 unsigned int enabled;
369 struct cel_config *cfg = ao2_global_obj_ref(cel_configs);
370
371 enabled = (!cfg || !cfg->general) ? 0 : cfg->general->enable;
372 ao2_cleanup(cfg);
373 return enabled;
374}
375
376static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
377{
378 unsigned int i;
379 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
381 struct ao2_iterator iter;
382 char *app;
383
384 switch (cmd) {
385 case CLI_INIT:
386 e->command = "cel show status";
387 e->usage =
388 "Usage: cel show status\n"
389 " Displays the Channel Event Logging system status.\n";
390 return NULL;
391 case CLI_GENERATE:
392 return NULL;
393 case CLI_HANDLER:
394 break;
395 }
396
397 if (a->argc > 3) {
398 return CLI_SHOWUSAGE;
399 }
400
401 ast_cli(a->fd, "CEL Logging: %s\n", ast_cel_check_enabled() ? "Enabled" : "Disabled");
402
403 if (!cfg || !cfg->general || !cfg->general->enable) {
404 return CLI_SUCCESS;
405 }
406
407 for (i = 0; i < (sizeof(cfg->general->events) * 8); i++) {
408 const char *name;
409
410 if (!(cfg->general->events & ((int64_t) 1 << i))) {
411 continue;
412 }
413
415 if (strcasecmp(name, "Unknown")) {
416 ast_cli(a->fd, "CEL Tracking Event: %s\n", name);
417 }
418 }
419
420 iter = ao2_iterator_init(cfg->general->apps, 0);
421 for (; (app = ao2_iterator_next(&iter)); ao2_ref(app, -1)) {
422 ast_cli(a->fd, "CEL Tracking Application: %s\n", app);
423 }
425
426 if (backends) {
427 struct cel_backend *backend;
428
429 iter = ao2_iterator_init(backends, 0);
430 for (; (backend = ao2_iterator_next(&iter)); ao2_ref(backend, -1)) {
431 ast_cli(a->fd, "CEL Event Subscriber: %s\n", backend->name);
432 }
434 }
435
436 return CLI_SUCCESS;
437}
438
439static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CEL status");
440
442{
443 unsigned int i;
444
445 for (i = 0; i < ARRAY_LEN(cel_event_types); i++) {
446 if (cel_event_types[i] && !strcasecmp(name, cel_event_types[i])) {
447 return i;
448 }
449 }
450
451 ast_log(LOG_ERROR, "Unknown event name '%s'\n", name);
453}
454
456{
457 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
458
459 if (!cfg || !cfg->general) {
460 return 0;
461 }
462
463 return (cfg->general->events & ((int64_t) 1 << et)) ? 1 : 0;
464}
465
466static int events_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
467{
468 struct ast_cel_general_config *cfg = obj;
469 char *events = ast_strdupa(var->value);
470 char *cur_event;
471
472 while ((cur_event = strsep(&events, ","))) {
473 enum ast_cel_event_type event_type;
474
475 cur_event = ast_strip(cur_event);
476 if (ast_strlen_zero(cur_event)) {
477 continue;
478 }
479
480 event_type = ast_cel_str_to_event_type(cur_event);
481
482 if (event_type == AST_CEL_ALL) {
483 /* All events */
484 cfg->events = (int64_t) -1;
485 } else if (event_type == AST_CEL_INVALID_VALUE) {
486 return -1;
487 } else {
488 cfg->events |= ((int64_t) 1 << event_type);
489 }
490 }
491
492 return 0;
493}
494
495static int apps_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
496{
497 struct ast_cel_general_config *cfg = obj;
498 char *apps = ast_strdupa(var->value);
499 char *cur_app;
500
501 while ((cur_app = strsep(&apps, ","))) {
502 cur_app = ast_strip(cur_app);
503 if (ast_strlen_zero(cur_app)) {
504 continue;
505 }
506
507 cur_app = ast_str_to_lower(cur_app);
508 ast_str_container_add(cfg->apps, cur_app);
509 }
510
511 return 0;
512}
513
515{
516 return S_OR(cel_event_types[type], "Unknown");
517}
518
519static int cel_track_app(const char *const_app)
520{
521 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
522 RAII_VAR(char *, app, NULL, ao2_cleanup);
523 char *app_lower;
524
525 if (!cfg || !cfg->general) {
526 return 0;
527 }
528
529 app_lower = ast_str_to_lower(ast_strdupa(const_app));
530 app = ao2_find(cfg->general->apps, app_lower, OBJ_SEARCH_KEY);
531 if (!app) {
532 return 0;
533 }
534
535 return 1;
536}
537
538static int cel_linkedid_ref(const char *linkedid);
539
541 enum ast_cel_event_type event_type, const char *userdefevname,
542 struct ast_json *extra, const char *peer)
543{
544 struct timeval eventtime = ast_tvnow();
545
546 return ast_cel_create_event_with_time(snapshot, event_type, &eventtime,
547 userdefevname, extra, peer);
548}
549
551 enum ast_cel_event_type event_type, const struct timeval *event_time,
552 const char *userdefevname, struct ast_json *extra, const char *peer)
553{
554 RAII_VAR(char *, extra_txt, NULL, ast_json_free);
555 if (extra) {
556 extra_txt = ast_json_dump_string(extra);
557 }
583}
584
585static int cel_backend_send_cb(void *obj, void *arg, int flags)
586{
587 struct cel_backend *backend = obj;
588
589 backend->callback(arg);
590 return 0;
591}
592
593static int cel_report_event(struct ast_channel_snapshot *snapshot,
594 enum ast_cel_event_type event_type, const struct timeval *event_time,
595 const char *userdefevname, struct ast_json *extra,
596 const char *peer_str)
597{
598 struct ast_event *ev;
599 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
601
602 if (!cfg || !cfg->general || !cfg->general->enable || !backends) {
603 return 0;
604 }
605
606 /* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
607 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
608 if (event_type == AST_CEL_CHANNEL_START
610 if (cel_linkedid_ref(snapshot->peer->linkedid)) {
611 return -1;
612 }
613 }
614
615 if (!ast_cel_track_event(event_type)) {
616 return 0;
617 }
618
619 if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
620 && !cel_track_app(snapshot->dialplan->appl)) {
621 return 0;
622 }
623
624 ev = ast_cel_create_event_with_time(snapshot, event_type, event_time, userdefevname, extra, peer_str);
625 if (!ev) {
626 return -1;
627 }
628
629 /* Distribute event to backends */
632
633 return 0;
634}
635
636/* called whenever a channel is destroyed or a linkedid is changed to
637 * potentially emit a CEL_LINKEDID_END event */
638static void check_retire_linkedid(struct ast_channel_snapshot *snapshot, const struct timeval *event_time)
639{
640 RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
641 struct cel_linkedid *lid;
642
643 if (!linkedids || ast_strlen_zero(snapshot->peer->linkedid)) {
644 /* The CEL module is shutdown. Abort. */
645 return;
646 }
647
648 ao2_lock(linkedids);
649
650 lid = ao2_find(linkedids, (void *) snapshot->peer->linkedid, OBJ_SEARCH_KEY);
651 if (!lid) {
652 ao2_unlock(linkedids);
653
654 /*
655 * The user may have done a reload to start tracking linkedids
656 * when a call was already in progress. This is an unusual kind
657 * of change to make after starting Asterisk.
658 */
659 ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n",
660 snapshot->peer->linkedid);
661 return;
662 }
663
664 if (!--lid->count) {
665 /* No channels use this linkedid anymore. */
666 ao2_unlink(linkedids, lid);
667 ao2_unlock(linkedids);
668
669 cel_report_event(snapshot, AST_CEL_LINKEDID_END, event_time, NULL, NULL, NULL);
670 } else {
671 ao2_unlock(linkedids);
672 }
673 ao2_ref(lid, -1);
674}
675
676/* Note that no 'chan_fixup' function is provided for this datastore type,
677 * because the channels that will use it will never be involved in masquerades.
678 */
680 .type = "CEL fabricated channel",
681 .destroy = ast_free_ptr,
682};
683
685{
686 struct varshead *headp;
687 struct ast_var_t *newvariable;
688 const char *mixed_name;
689 char timebuf[30];
690 struct ast_channel *tchan;
691 struct ast_cel_event_record record = {
693 };
694 struct ast_datastore *datastore;
695 char *app_data;
696 RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
697
698 if (!cfg || !cfg->general) {
699 return NULL;
700 }
701
702 /* do not call ast_channel_alloc because this is not really a real channel */
703 if (!(tchan = ast_dummy_channel_alloc())) {
704 return NULL;
705 }
706
707 headp = ast_channel_varshead(tchan);
708
709 /* first, get the variables from the event */
710 if (ast_cel_fill_record(event, &record)) {
711 ast_channel_unref(tchan);
712 return NULL;
713 }
714
715 /* next, fill the channel with their data */
716 mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
717 ? record.user_defined_name : record.event_name;
718 if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
719 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
720 }
721
722 if (ast_strlen_zero(cfg->general->date_format)) {
723 snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
724 (long) record.event_time.tv_usec);
725 } else {
726 struct ast_tm tm;
727 ast_localtime(&record.event_time, &tm, NULL);
728 ast_strftime(timebuf, sizeof(timebuf), cfg->general->date_format, &tm);
729 }
730
731 if ((newvariable = ast_var_assign("eventtime", timebuf))) {
732 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
733 }
734
735 if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
736 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
737 }
738 if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
739 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
740 }
741 if ((newvariable = ast_var_assign("eventextra", record.extra))) {
742 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
743 }
744
745 ast_channel_caller(tchan)->id.name.valid = 1;
747 ast_channel_caller(tchan)->id.number.valid = 1;
754
755 ast_channel_exten_set(tchan, record.extension);
756 ast_channel_context_set(tchan, record.context);
757 ast_channel_name_set(tchan, record.channel_name);
759 ast_channel_accountcode_set(tchan, record.account_code);
760 ast_channel_peeraccount_set(tchan, record.peer_account);
761 ast_channel_userfield_set(tchan, record.user_field);
762
763 if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
764 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
765 }
766
767 ast_channel_amaflags_set(tchan, record.amaflag);
768
769 /* We need to store an 'application name' and 'application
770 * data' on the channel for logging purposes, but the channel
771 * structure only provides a place to store pointers, and it
772 * expects these pointers to be pointing to data that does not
773 * need to be freed. This means that the channel's destructor
774 * does not attempt to free any storage that these pointers
775 * point to. However, we can't provide data in that form directly for
776 * these structure members. In order to ensure that these data
777 * elements have a lifetime that matches the channel's
778 * lifetime, we'll put them in a datastore attached to the
779 * channel, and set's the channel's pointers to point into the
780 * datastore. The datastore will then be automatically destroyed
781 * when the channel is destroyed.
782 */
783
785 ast_channel_unref(tchan);
786 return NULL;
787 }
788
789 if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
790 ast_datastore_free(datastore);
791 ast_channel_unref(tchan);
792 return NULL;
793 }
794
795 ast_channel_appl_set(tchan, strcpy(app_data, record.application_name));
796 ast_channel_data_set(tchan, strcpy(app_data + strlen(record.application_name) + 1,
797 record.application_data));
798
799 datastore->data = app_data;
800 ast_channel_datastore_add(tchan, datastore);
801
802 return tchan;
803}
804
805static int cel_linkedid_ref(const char *linkedid)
806{
807 RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
808 struct cel_linkedid *lid;
809
810 if (ast_strlen_zero(linkedid)) {
811 ast_log(LOG_ERROR, "The linkedid should never be empty\n");
812 return -1;
813 }
814 if (!linkedids) {
815 /* The CEL module is shutdown. Abort. */
816 return -1;
817 }
818
819 ao2_lock(linkedids);
820 lid = ao2_find(linkedids, (void *) linkedid, OBJ_SEARCH_KEY);
821 if (!lid) {
822 /*
823 * Changes to the lid->count member are protected by the
824 * container lock so the lid object does not need its own lock.
825 */
826 lid = ao2_alloc_options(sizeof(*lid) + strlen(linkedid) + 1, NULL,
828 if (!lid) {
829 ao2_unlock(linkedids);
830 return -1;
831 }
832 strcpy(lid->id, linkedid);/* Safe */
833
834 ao2_link(linkedids, lid);
835 }
836 ++lid->count;
837 ao2_unlock(linkedids);
838 ao2_ref(lid, -1);
839
840 return 0;
841}
842
844{
846 ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record. "
847 "Please ensure all modules were compiled for "
848 "this version of Asterisk.\n");
849 return -1;
850 }
851
853
856
858
879
880 return 0;
881}
882
883/*! \brief Typedef for callbacks that get called on channel snapshot updates */
885 struct ast_channel_snapshot *old_snapshot,
886 struct ast_channel_snapshot *new_snapshot,
887 const struct timeval *event_time);
888
889static struct cel_dialstatus *get_dialstatus(const char *uniqueid)
890{
891 struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
893
894 if (dial_statuses) {
896 ao2_ref(dial_statuses, -1);
897 }
898 return dialstatus;
899}
900
901static const char *get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
902{
903 struct ast_json *json = ast_multi_channel_blob_get_json(blob);
904 if (!json) {
905 return NULL;
906 }
907
908 json = ast_json_object_get(json, varname);
909 if (!json) {
910 return NULL;
911 }
912
913 return ast_json_string_get(json);
914}
915
916/*! \brief Handle channel state changes */
918 struct ast_channel_snapshot *old_snapshot,
919 struct ast_channel_snapshot *new_snapshot,
920 const struct timeval *event_time)
921{
922 int is_hungup, was_hungup;
923
924 if (!old_snapshot) {
925 cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, event_time, NULL, NULL, NULL);
926 return;
927 }
928
929 was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
930 is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
931
932 if (!was_hungup && is_hungup) {
933 struct ast_json *extra;
934 struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->base->uniqueid);
935
936 extra = ast_json_pack("{s: i, s: s, s: s}",
937 "hangupcause", new_snapshot->hangup->cause,
938 "hangupsource", new_snapshot->hangup->source,
939 "dialstatus", dialstatus ? dialstatus->dialstatus : "");
940 cel_report_event(new_snapshot, AST_CEL_HANGUP, event_time, NULL, extra, NULL);
941 ast_json_unref(extra);
943
944 cel_report_event(new_snapshot, AST_CEL_CHANNEL_END, event_time, NULL, NULL, NULL);
946 check_retire_linkedid(new_snapshot, event_time);
947 }
948 return;
949 }
950
951 if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
952 cel_report_event(new_snapshot, AST_CEL_ANSWER, event_time, NULL, NULL, NULL);
953 return;
954 }
955}
956
958 struct ast_channel_snapshot *old_snapshot,
959 struct ast_channel_snapshot *new_snapshot,
960 const struct timeval *event_time)
961{
962 if (!old_snapshot) {
963 return;
964 }
965
966 ast_assert(!ast_strlen_zero(new_snapshot->peer->linkedid));
967 ast_assert(!ast_strlen_zero(old_snapshot->peer->linkedid));
968
970 && strcmp(old_snapshot->peer->linkedid, new_snapshot->peer->linkedid)) {
971 cel_linkedid_ref(new_snapshot->peer->linkedid);
972 check_retire_linkedid(old_snapshot, event_time);
973 }
974}
975
977 struct ast_channel_snapshot *old_snapshot,
978 struct ast_channel_snapshot *new_snapshot,
979 const struct timeval *event_time)
980{
981 if (old_snapshot && !strcmp(old_snapshot->dialplan->appl, new_snapshot->dialplan->appl)) {
982 return;
983 }
984
985 /* old snapshot has an application, end it */
986 if (old_snapshot && !ast_strlen_zero(old_snapshot->dialplan->appl)) {
987 cel_report_event(old_snapshot, AST_CEL_APP_END, event_time, NULL, NULL, NULL);
988 }
989
990 /* new snapshot has an application, start it */
991 if (!ast_strlen_zero(new_snapshot->dialplan->appl)) {
992 cel_report_event(new_snapshot, AST_CEL_APP_START, event_time, NULL, NULL, NULL);
993 }
994}
995
996/*! \brief Handlers for channel snapshot changes.
997 * \note Order of the handlers matters. Application changes must come before state
998 * changes to ensure that hangup notifications occur after application changes.
999 * Linkedid checking should always come last.
1000 */
1005};
1006
1008{
1009 if (!snapshot) {
1010 return 0;
1011 }
1012 return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
1013}
1014
1015static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
1016 struct stasis_message *message)
1017{
1019 size_t i;
1020
1021 if (cel_filter_channel_snapshot(update->old_snapshot) || cel_filter_channel_snapshot(update->new_snapshot)) {
1022 return;
1023 }
1024
1025 for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {
1026 cel_channel_monitors[i](update->old_snapshot, update->new_snapshot, stasis_message_timestamp(message));
1027 }
1028}
1029
1031 struct ast_bridge_snapshot *bridge,
1032 struct ast_channel_snapshot *chan)
1033{
1034 struct ast_str *peer_str = ast_str_create(32);
1035 struct ao2_iterator i;
1036 char *current_chan = NULL;
1037
1038 if (!peer_str) {
1039 return NULL;
1040 }
1041
1042 for (i = ao2_iterator_init(bridge->channels, 0);
1043 (current_chan = ao2_iterator_next(&i));
1044 ao2_cleanup(current_chan)) {
1045 struct ast_channel_snapshot *current_snapshot;
1046
1047 /* Don't add the channel for which this message is being generated */
1048 if (!strcmp(current_chan, chan->base->uniqueid)) {
1049 continue;
1050 }
1051
1052 current_snapshot = ast_channel_snapshot_get_latest(current_chan);
1053 if (!current_snapshot) {
1054 continue;
1055 }
1056
1057 ast_str_append(&peer_str, 0, "%s,", current_snapshot->base->name);
1058 ao2_cleanup(current_snapshot);
1059 }
1061
1062 /* Rip off the trailing comma */
1063 ast_str_truncate(peer_str, -1);
1064
1065 return peer_str;
1066}
1067
1069 void *data, struct stasis_subscription *sub,
1070 struct stasis_message *message)
1071{
1073 struct ast_bridge_snapshot *snapshot = blob->bridge;
1074 struct ast_channel_snapshot *chan_snapshot = blob->channel;
1075 RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1076 RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
1077
1078 if (cel_filter_channel_snapshot(chan_snapshot)) {
1079 return;
1080 }
1081
1082 extra = ast_json_pack("{s: s, s: s}",
1083 "bridge_id", snapshot->uniqueid,
1084 "bridge_technology", snapshot->technology);
1085 if (!extra) {
1086 return;
1087 }
1088
1089 peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
1090 if (!peer_str) {
1091 return;
1092 }
1093
1095 NULL, extra, ast_str_buffer(peer_str));
1096}
1097
1099 void *data, struct stasis_subscription *sub,
1100 struct stasis_message *message)
1101{
1103 struct ast_bridge_snapshot *snapshot = blob->bridge;
1104 struct ast_channel_snapshot *chan_snapshot = blob->channel;
1105 RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1106 RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
1107
1108 if (cel_filter_channel_snapshot(chan_snapshot)) {
1109 return;
1110 }
1111
1112 extra = ast_json_pack("{s: s, s: s}",
1113 "bridge_id", snapshot->uniqueid,
1114 "bridge_technology", snapshot->technology);
1115 if (!extra) {
1116 return;
1117 }
1118
1119 peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
1120 if (!peer_str) {
1121 return;
1122 }
1123
1125 NULL, extra, ast_str_buffer(peer_str));
1126}
1127
1128static void cel_parking_cb(
1129 void *data, struct stasis_subscription *sub,
1130 struct stasis_message *message)
1131{
1132 struct ast_parked_call_payload *parked_payload = stasis_message_data(message);
1133 RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1134 const char *reason = NULL;
1135
1136 switch (parked_payload->event_type) {
1137 case PARKED_CALL:
1138 extra = ast_json_pack("{s: s, s: s}",
1139 "parker_dial_string", parked_payload->parker_dial_string,
1140 "parking_lot", parked_payload->parkinglot);
1141 if (extra) {
1143 NULL, extra, NULL);
1144 }
1145 return;
1147 reason = "ParkedCallTimeOut";
1148 break;
1149 case PARKED_CALL_GIVEUP:
1150 reason = "ParkedCallGiveUp";
1151 break;
1153 reason = "ParkedCallUnparked";
1154 break;
1155 case PARKED_CALL_FAILED:
1156 reason = "ParkedCallFailed";
1157 break;
1158 case PARKED_CALL_SWAP:
1159 reason = "ParkedCallSwap";
1160 break;
1161 }
1162
1163 if (parked_payload->retriever) {
1164 extra = ast_json_pack("{s: s, s: s}",
1165 "reason", reason ?: "",
1166 "retriever", parked_payload->retriever->base->name);
1167 } else {
1168 extra = ast_json_pack("{s: s}", "reason", reason ?: "");
1169 }
1170
1171 if (extra) {
1173 NULL, extra, NULL);
1174 }
1175}
1176
1177static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_channel_snapshot *snapshot)
1178{
1179 struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
1180 const char *dialstatus_string = get_blob_variable(blob, "dialstatus");
1181 struct cel_dialstatus *dialstatus;
1182 size_t dialstatus_string_len;
1183
1184 if (!dial_statuses || ast_strlen_zero(dialstatus_string)) {
1185 ao2_cleanup(dial_statuses);
1186 return;
1187 }
1188
1189 dialstatus = ao2_find(dial_statuses, snapshot->base->uniqueid, OBJ_SEARCH_KEY);
1190 if (dialstatus) {
1191 if (!strcasecmp(dialstatus_string, "ANSWER") && strcasecmp(dialstatus->dialstatus, "ANSWER")) {
1192 /* In the case of an answer after we already have a dial status we give
1193 * priority to the answer since the call was, well, answered. In the case of
1194 * failure dial status results we simply let the first failure be the status.
1195 */
1196 ao2_unlink(dial_statuses, dialstatus);
1197 ao2_ref(dialstatus, -1);
1198 } else {
1199 ao2_ref(dialstatus, -1);
1200 ao2_ref(dial_statuses, -1);
1201 return;
1202 }
1203 }
1204
1205 dialstatus_string_len = strlen(dialstatus_string) + 1;
1206 dialstatus = ao2_alloc_options(sizeof(*dialstatus) + dialstatus_string_len, NULL,
1208 if (!dialstatus) {
1209 ao2_ref(dial_statuses, -1);
1210 return;
1211 }
1212
1213 ast_copy_string(dialstatus->uniqueid, snapshot->base->uniqueid, sizeof(dialstatus->uniqueid));
1214 ast_copy_string(dialstatus->dialstatus, dialstatus_string, dialstatus_string_len);
1215
1216 ao2_link(dial_statuses, dialstatus);
1217 ao2_ref(dialstatus, -1);
1218 ao2_ref(dial_statuses, -1);
1219}
1220
1222{
1223 const char *dialstatus = get_blob_variable(blob, "dialstatus");
1224 int res = 0;
1225
1227 res = 0;
1228 } else if (!strcasecmp(dialstatus, "CHANUNAVAIL")) {
1229 res = 1;
1230 } else if (!strcasecmp(dialstatus, "CONGESTION")) {
1231 res = 1;
1232 } else if (!strcasecmp(dialstatus, "NOANSWER")) {
1233 res = 1;
1234 } else if (!strcasecmp(dialstatus, "BUSY")) {
1235 res = 1;
1236 } else if (!strcasecmp(dialstatus, "ANSWER")) {
1237 res = 1;
1238 } else if (!strcasecmp(dialstatus, "CANCEL")) {
1239 res = 1;
1240 } else if (!strcasecmp(dialstatus, "DONTCALL")) {
1241 res = 1;
1242 } else if (!strcasecmp(dialstatus, "TORTURE")) {
1243 res = 1;
1244 } else if (!strcasecmp(dialstatus, "INVALIDARGS")) {
1245 res = 1;
1246 }
1247 return res;
1248}
1249
1250static void cel_dial_cb(void *data, struct stasis_subscription *sub,
1251 struct stasis_message *message)
1252{
1254 struct ast_channel_snapshot *snapshot;
1255
1256 snapshot = ast_multi_channel_blob_get_channel(blob, "caller");
1257 if (!snapshot || cel_filter_channel_snapshot(snapshot)) {
1258 return;
1259 }
1260
1261 if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
1262 struct ast_json *extra;
1263
1264 extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
1265 if (extra) {
1267 NULL, extra, NULL);
1268 ast_json_unref(extra);
1269 }
1270 }
1271
1272 if (is_valid_dialstatus(blob)) {
1273 save_dialstatus(blob, snapshot);
1274 }
1275}
1276
1277static void cel_generic_cb(
1278 void *data, struct stasis_subscription *sub,
1279 struct stasis_message *message)
1280{
1282 int event_type = ast_json_integer_get(ast_json_object_get(obj->blob, "event_type"));
1283 struct ast_json *event_details = ast_json_object_get(obj->blob, "event_details");
1284
1285 switch (event_type) {
1287 case AST_CEL_DTMF:
1289 {
1290 const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
1291 struct ast_json *extra = ast_json_object_get(event_details, "extra");
1293 event, extra, NULL);
1294 break;
1295 }
1296 case AST_CEL_STREAM_END:
1297 {
1298 const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
1300 event, NULL, NULL);
1301 break;
1302 }
1303 default:
1304 ast_log(LOG_ERROR, "Unhandled %s event blob\n", ast_cel_get_type_name(event_type));
1305 break;
1306 }
1307}
1308
1310 void *data, struct stasis_subscription *sub,
1311 struct stasis_message *message)
1312{
1314 struct ast_channel_snapshot *chan_snapshot = transfer_msg->transferer;
1315 struct ast_bridge_snapshot *bridge_snapshot = transfer_msg->bridge;
1316 struct ast_json *extra;
1317
1318 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
1319 return;
1320 }
1321
1322 extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
1323 "extension", transfer_msg->exten,
1324 "context", transfer_msg->context,
1325 "bridge_id", bridge_snapshot->uniqueid,
1326 "transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->base->name : "N/A",
1327 "transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->base->uniqueid : "N/A");
1328 if (extra) {
1330 NULL, extra, NULL);
1331 ast_json_unref(extra);
1332 }
1333}
1334
1336 void *data, struct stasis_subscription *sub,
1337 struct stasis_message *message)
1338{
1340 struct ast_json *extra = NULL;
1341 struct ast_bridge_snapshot *bridge1, *bridge2;
1342 struct ast_channel_snapshot *channel1, *channel2;
1343
1344 /* Make sure bridge1 is always non-NULL */
1345 if (!xfer->to_transferee.bridge_snapshot) {
1346 bridge1 = xfer->to_transfer_target.bridge_snapshot;
1347 bridge2 = xfer->to_transferee.bridge_snapshot;
1348 channel1 = xfer->to_transfer_target.channel_snapshot;
1349 channel2 = xfer->to_transferee.channel_snapshot;
1350 } else {
1351 bridge1 = xfer->to_transferee.bridge_snapshot;
1352 bridge2 = xfer->to_transfer_target.bridge_snapshot;
1353 channel1 = xfer->to_transferee.channel_snapshot;
1354 channel2 = xfer->to_transfer_target.channel_snapshot;
1355 }
1356
1357 switch (xfer->dest_type) {
1359 return;
1360 /* handle these three the same */
1364 extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
1365 "bridge1_id", bridge1->uniqueid,
1366 "channel2_name", channel2->base->name,
1367 "channel2_uniqueid", channel2->base->uniqueid,
1368 "bridge2_id", bridge2->uniqueid,
1369 "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
1370 "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
1371 "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
1372 "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
1373 if (!extra) {
1374 return;
1375 }
1376 break;
1379 extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
1380 "bridge1_id", bridge1->uniqueid,
1381 "channel2_name", channel2->base->name,
1382 "channel2_uniqueid", channel2->base->uniqueid,
1383 "app", xfer->dest.app,
1384 "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
1385 "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
1386 "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
1387 "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
1388 if (!extra) {
1389 return;
1390 }
1391 break;
1392 }
1394 NULL, extra, NULL);
1395 ast_json_unref(extra);
1396}
1397
1398static void cel_pickup_cb(
1399 void *data, struct stasis_subscription *sub,
1400 struct stasis_message *message)
1401{
1403 struct ast_channel_snapshot *channel = ast_multi_channel_blob_get_channel(obj, "channel");
1404 struct ast_channel_snapshot *target = ast_multi_channel_blob_get_channel(obj, "target");
1405 struct ast_json *extra;
1406
1407 if (!channel || !target) {
1408 return;
1409 }
1410
1411 extra = ast_json_pack("{s: s, s: s}",
1412 "pickup_channel", channel->base->name,
1413 "pickup_channel_uniqueid", channel->base->uniqueid);
1414 if (!extra) {
1415 return;
1416 }
1417
1419 ast_json_unref(extra);
1420}
1421
1422
1424 void *data, struct stasis_subscription *sub,
1425 struct stasis_message *message,
1426 enum ast_cel_event_type event_type)
1427{
1429 struct ast_channel_snapshot *localone = ast_multi_channel_blob_get_channel(obj, "1");
1430 struct ast_channel_snapshot *localtwo = ast_multi_channel_blob_get_channel(obj, "2");
1431 struct ast_json *extra;
1432
1433 if (!localone || !localtwo) {
1434 return;
1435 }
1436
1437 extra = ast_json_pack("{s: s, s: s}",
1438 "local_two", localtwo->base->name,
1439 "local_two_uniqueid", localtwo->base->uniqueid);
1440 if (!extra) {
1441 return;
1442 }
1443
1444 cel_report_event(localone, event_type, stasis_message_timestamp(message), NULL, extra, NULL);
1445 ast_json_unref(extra);
1446}
1447
1449 void *data, struct stasis_subscription *sub,
1450 struct stasis_message *message)
1451{
1452 /* The AST_CEL_LOCAL_OPTIMIZE event has always been triggered by the end of optimization.
1453 This can either be used as an indication that the call was locally optimized, or as
1454 the END event in combination with the subsequently added BEGIN event. */
1456}
1457
1459 void *data, struct stasis_subscription *sub,
1460 struct stasis_message *message)
1461{
1463}
1464
1465static void destroy_routes(void)
1466{
1469}
1470
1471static void destroy_subscriptions(void)
1472{
1476 cel_topic = NULL;
1477
1482}
1483
1484static int unload_module(void)
1485{
1489
1491 aco_info_destroy(&cel_cfg_info);
1492 ao2_global_obj_release(cel_configs);
1493 ao2_global_obj_release(cel_dialstatus_store);
1494 ao2_global_obj_release(cel_linkedids);
1495 ao2_global_obj_release(cel_backends);
1496
1497 return 0;
1498}
1499
1500/*!
1501 * \brief Create the Stasis subscriptions for CEL
1502 */
1503static int create_subscriptions(void)
1504{
1505 cel_aggregation_topic = stasis_topic_create("cel:aggregator");
1506 if (!cel_aggregation_topic) {
1507 return -1;
1508 }
1509
1510 cel_topic = stasis_topic_create("cel:misc");
1511 if (!cel_topic) {
1512 return -1;
1513 }
1514
1518 if (!cel_channel_forwarder) {
1519 return -1;
1520 }
1521
1525 if (!cel_bridge_forwarder) {
1526 return -1;
1527 }
1528
1532 if (!cel_parking_forwarder) {
1533 return -1;
1534 }
1535
1537 ast_cel_topic(),
1539 if (!cel_cel_forwarder) {
1540 return -1;
1541 }
1542
1543 return 0;
1544}
1545
1546/*!
1547 * \brief Create the Stasis message router and routes for CEL
1548 */
1549static int create_routes(void)
1550{
1551 int ret = 0;
1552
1554 if (!cel_state_router) {
1555 return -1;
1556 }
1559
1563 NULL);
1564
1568 NULL);
1569
1573 NULL);
1574
1578 NULL);
1579
1583 NULL);
1584
1588 NULL);
1589
1593 NULL);
1594
1598 NULL);
1599
1603 NULL);
1604
1608 NULL);
1609
1613 NULL);
1614
1615 if (ret) {
1616 ast_log(AST_LOG_ERROR, "Failed to register for Stasis messages\n");
1617 }
1618
1619 return ret;
1620}
1621
1624
1625static int load_module(void)
1626{
1627 struct ao2_container *container;
1628
1630 NUM_APP_BUCKETS, cel_linkedid_hash_fn, NULL, cel_linkedid_cmp_fn);
1633 if (!container) {
1635 }
1636
1638 NUM_DIALSTATUS_BUCKETS, cel_dialstatus_hash_fn, NULL, cel_dialstatus_cmp_fn);
1639 ao2_global_obj_replace_unref(cel_dialstatus_store, container);
1641 if (!container) {
1643 }
1644
1647 }
1648
1651 }
1652
1654 cel_backend_hash_fn, NULL, cel_backend_cmp_fn);
1657 if (!container) {
1659 }
1660
1661 if (aco_info_init(&cel_cfg_info)) {
1663 }
1664
1665 aco_option_register(&cel_cfg_info, "enable", ACO_EXACT, general_options, "no", OPT_BOOL_T, 1, FLDSET(struct ast_cel_general_config, enable));
1666 aco_option_register(&cel_cfg_info, "dateformat", ACO_EXACT, general_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_cel_general_config, date_format));
1667 aco_option_register_custom(&cel_cfg_info, "apps", ACO_EXACT, general_options, "", apps_handler, 0);
1668 aco_option_register_custom(&cel_cfg_info, "events", ACO_EXACT, general_options, "", events_handler, 0);
1669
1670 if (aco_process_config(&cel_cfg_info, 0)) {
1671 struct cel_config *cel_cfg = cel_config_alloc();
1672
1673 if (!cel_cfg) {
1675 }
1676
1677 /* We couldn't process the configuration so create a default config. */
1678 if (!aco_set_defaults(&general_option, "general", cel_cfg->general)) {
1679 ast_log(LOG_NOTICE, "Failed to process CEL configuration; using defaults\n");
1680 ao2_global_obj_replace_unref(cel_configs, cel_cfg);
1681 }
1682 ao2_ref(cel_cfg, -1);
1683 }
1684
1685 if (create_subscriptions()) {
1687 }
1688
1691 }
1692
1694}
1695
1696static int reload_module(void)
1697{
1698 unsigned int was_enabled = ast_cel_check_enabled();
1699 unsigned int is_enabled;
1700
1701 if (aco_process_config(&cel_cfg_info, 1) == ACO_PROCESS_ERROR) {
1702 return -1;
1703 }
1704
1706
1707 if (!was_enabled && is_enabled) {
1708 if (create_routes()) {
1709 return -1;
1710 }
1711 } else if (was_enabled && !is_enabled) {
1713 }
1714
1715 ast_verb(3, "CEL logging %sabled.\n", is_enabled ? "en" : "dis");
1716
1717 return 0;
1718}
1719
1721 const char *event,
1722 const char *extra)
1723{
1724 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1725
1726 blob = ast_json_pack("{s: s, s: {s: s}}",
1727 "event", event,
1728 "extra", "extra", S_OR(extra, ""));
1729 if (!blob) {
1730 return;
1731 }
1733}
1734
1736 enum ast_cel_event_type event_type,
1737 struct ast_json *blob)
1738{
1739 struct ast_json *cel_blob;
1740 struct stasis_message *message;
1741
1742 cel_blob = ast_json_pack("{s: i, s: o}",
1743 "event_type", event_type,
1744 "event_details", ast_json_ref(blob));
1745
1747 if (message) {
1749 }
1751 ast_json_unref(cel_blob);
1752}
1753
1755{
1756 return cel_topic;
1757}
1758
1760{
1761 RAII_VAR(struct cel_config *, mod_cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
1762
1763 if (!mod_cfg || !mod_cfg->general) {
1764 return NULL;
1765 }
1766
1767 ao2_ref(mod_cfg->general, +1);
1768 return mod_cfg->general;
1769}
1770
1772{
1773 int was_enabled;
1774 int is_enabled;
1775 struct ast_cel_general_config *cleanup_config;
1776 struct cel_config *mod_cfg = ao2_global_obj_ref(cel_configs);
1777
1778 if (mod_cfg) {
1779 was_enabled = ast_cel_check_enabled();
1780
1781 cleanup_config = mod_cfg->general;
1783 mod_cfg->general = config;
1784 ao2_cleanup(cleanup_config);
1785
1787 if (!was_enabled && is_enabled) {
1788 create_routes();
1789 } else if (was_enabled && !is_enabled) {
1791 }
1792
1793 ao2_ref(mod_cfg, -1);
1794 }
1795}
1796
1798{
1799 struct ao2_container *backends = ao2_global_obj_ref(cel_backends);
1800
1801 if (backends) {
1803 ao2_ref(backends, -1);
1804 }
1805
1806 return 0;
1807}
1808
1809int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
1810{
1812 struct cel_backend *backend;
1813
1814 if (!backends || ast_strlen_zero(name) || !backend_callback) {
1815 return -1;
1816 }
1817
1818 /* The backend object is immutable so it doesn't need a lock of its own. */
1819 backend = ao2_alloc_options(sizeof(*backend) + 1 + strlen(name), NULL,
1821 if (!backend) {
1822 return -1;
1823 }
1824 strcpy(backend->name, name);/* Safe */
1825 backend->callback = backend_callback;
1826
1827 ao2_link(backends, backend);
1828 ao2_ref(backend, -1);
1829 return 0;
1830}
1831
1833 .support_level = AST_MODULE_SUPPORT_CORE,
1834 .load = load_module,
1835 .unload = unload_module,
1837 .load_pri = AST_MODPRI_CORE,
1838 .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:1465
void ast_cel_publish_user_event(struct ast_channel *chan, const char *event, const char *extra)
Publish a CEL user event.
Definition: cel.c:1720
static struct aco_type ignore_option
Definition: cel.c:275
void ast_cel_set_config(struct ast_cel_general_config *config)
Set the current CEL configuration.
Definition: cel.c:1771
static int cel_linkedid_ref(const char *linkedid)
Definition: cel.c:805
static void cel_general_config_dtor(void *obj)
Destructor for cel_config.
Definition: cel.c:199
static const char * ignore_categories[]
Definition: cel.c:269
#define BACKEND_BUCKETS
Definition: cel.c:160
static struct ast_cli_entry cli_status
Definition: cel.c:439
static struct stasis_forward * cel_cel_forwarder
Definition: cel.c:151
static int cel_report_event(struct ast_channel_snapshot *snapshot, enum ast_cel_event_type event_type, const struct timeval *event_time, const char *userdefevname, struct ast_json *extra, const char *peer_str)
Definition: cel.c:593
static int ast_cel_track_event(enum ast_cel_event_type et)
Definition: cel.c:455
#define CEL_MAX_EVENT_IDS
Maximum possible CEL event IDs.
Definition: cel.c:169
static int create_subscriptions(void)
Create the Stasis subscriptions for CEL.
Definition: cel.c:1503
static void cel_local_optimization_end_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1448
int ast_cel_backend_unregister(const char *name)
Unregister a CEL backend.
Definition: cel.c:1797
static const char *const cel_event_types[CEL_MAX_EVENT_IDS]
Map of ast_cel_event_type to strings.
Definition: cel.c:324
void(* cel_channel_snapshot_monitor)(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot, const struct timeval *event_time)
Typedef for callbacks that get called on channel snapshot updates.
Definition: cel.c:884
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:540
static int create_routes(void)
Create the Stasis message router and routes for CEL.
Definition: cel.c:1549
static int is_valid_dialstatus(struct ast_multi_channel_blob *blob)
Definition: cel.c:1221
static struct aco_type general_option
An aco_type structure to link the "general" category to the ast_cel_general_config type.
Definition: cel.c:260
enum ast_cel_event_type ast_cel_str_to_event_type(const char *name)
Get the event type from a string.
Definition: cel.c:441
void ast_cel_publish_event(struct ast_channel *chan, enum ast_cel_event_type event_type, struct ast_json *blob)
Publish a CEL event.
Definition: cel.c:1735
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:957
static void cel_bridge_leave_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1098
static void cel_dial_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1250
static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1015
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:466
void * ast_cel_general_config_alloc(void)
Allocate a CEL configuration object.
Definition: cel.c:207
unsigned int ast_cel_check_enabled(void)
Hashing function for cel_backend.
Definition: cel.c:366
#define NUM_DIALSTATUS_BUCKETS
Number of buckets for the dialstatus container.
Definition: cel.c:179
static struct aco_file cel_conf
The config file to be processed for the module.
Definition: cel.c:283
static int reload_module(void)
Definition: cel.c:1696
static void check_retire_linkedid(struct ast_channel_snapshot *snapshot, const struct timeval *event_time)
Definition: cel.c:638
static int cel_filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
Definition: cel.c:1007
static void cel_pickup_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1398
static void cel_blind_transfer_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1309
static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_channel_snapshot *snapshot)
Definition: cel.c:1177
struct stasis_topic * ast_cel_topic(void)
Get the CEL topic.
Definition: cel.c:1754
static struct aco_type * general_options[]
Definition: cel.c:319
static void cel_config_dtor(void *obj)
Destructor for cel_config.
Definition: cel.c:236
static void cel_attended_transfer_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1335
static int cel_track_app(const char *const_app)
Definition: cel.c:519
struct ast_channel * ast_cel_fabricate_channel_from_event(const struct ast_event *event)
Create a fake channel from data in a CEL event.
Definition: cel.c:684
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:843
static const char * get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
Definition: cel.c:901
static int cel_pre_apply_config(void)
Definition: cel.c:295
static void cel_channel_state_change(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot, const struct timeval *event_time)
Handle channel state changes.
Definition: cel.c:917
static struct stasis_forward * cel_channel_forwarder
Definition: cel.c:142
cel_channel_snapshot_monitor cel_channel_monitors[]
Handlers for channel snapshot changes.
Definition: cel.c:1001
struct stasis_message_type * cel_generic_type(void)
static char * handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cel.c:376
static int load_module(void)
Definition: cel.c:1625
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:585
static void cel_channel_app_change(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot, const struct timeval *event_time)
Definition: cel.c:976
static int apps_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition: cel.c:495
static struct ast_str * cel_generate_peer_str(struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *chan)
Definition: cel.c:1030
#define NUM_APP_BUCKETS
Number of buckets for the appset container.
Definition: cel.c:174
static const struct ast_datastore_info fabricated_channel_datastore
Definition: cel.c:679
static void cel_generic_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1277
static struct stasis_forward * cel_bridge_forwarder
Definition: cel.c:145
static void cel_parking_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1128
static struct stasis_message_router * cel_state_router
Definition: cel.c:133
static struct stasis_topic * cel_topic
Definition: cel.c:136
static int unload_module(void)
Definition: cel.c:1484
static struct cel_dialstatus * get_dialstatus(const char *uniqueid)
Definition: cel.c:889
struct ast_cel_general_config * ast_cel_get_config(void)
Obtain the current CEL configuration.
Definition: cel.c:1759
static void * cel_config_alloc(void)
Definition: cel.c:243
int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
Register a CEL backend.
Definition: cel.c:1809
const char * ast_cel_get_type_name(enum ast_cel_event_type type)
Get the name of a CEL event type.
Definition: cel.c:514
static void destroy_subscriptions(void)
Definition: cel.c:1471
static struct stasis_forward * cel_parking_forwarder
Definition: cel.c:148
struct ast_event * ast_cel_create_event_with_time(struct ast_channel_snapshot *snapshot, enum ast_cel_event_type event_type, const struct timeval *event_time, const char *userdefevname, struct ast_json *extra, const char *peer)
Allocate and populate a CEL event structure.
Definition: cel.c:550
static void cel_local_optimization_begin_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1458
static void cel_bridge_enter_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cel.c:1068
static struct stasis_topic * cel_aggregation_topic
Definition: cel.c:139
static void cel_local_optimization_cb_helper(void *data, struct stasis_subscription *sub, struct stasis_message *message, enum ast_cel_event_type event_type)
Definition: cel.c:1423
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_DTMF
A DTMF digit was processed.
Definition: cel.h:85
@ 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_STREAM_BEGIN
A stream started.
Definition: cel.h:81
@ AST_CEL_ATTENDEDTRANSFER
a transfer occurs
Definition: cel.h:67
@ AST_CEL_BRIDGE_ENTER
channel enters a bridge
Definition: cel.h:57
@ AST_CEL_STREAM_END
A stream ended.
Definition: cel.h:83
@ 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:317
#define AST_CEL_EVENT_RECORD_VERSION
struct ABI version
Definition: cel.h:149
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:2355
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)
@ AST_FLAG_DEAD
Definition: channel.h:1065
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:3008
#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_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:991
void ast_channel_name_set(struct ast_channel *chan, const char *value)
@ AST_STATE_UP
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:2408
#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:96
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
struct ast_bridge_channel_snapshot_pair to_transfer_target
struct ast_channel_snapshot * transferee
union ast_attended_transfer_message::@289 dest
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:144
const char * caller_id_dnid
Definition: cel.h:163
const char * application_data
Definition: cel.h:168
const char * account_code
Definition: cel.h:169
const char * caller_id_rdnis
Definition: cel.h:162
const char * extra
Definition: cel.h:177
const char * extension
Definition: cel.h:164
const char * caller_id_num
Definition: cel.h:160
const char * channel_name
Definition: cel.h:166
const char * linked_id
Definition: cel.h:172
const char * peer_account
Definition: cel.h:170
const char * peer
Definition: cel.h:176
enum ast_cel_event_type event_type
Definition: cel.h:155
const char * unique_id
Definition: cel.h:171
const char * user_defined_name
Definition: cel.h:158
const char * context
Definition: cel.h:165
const char * application_name
Definition: cel.h:167
struct timeval event_time
Definition: cel.h:156
uint32_t version
struct ABI version
Definition: cel.h:154
const char * tenant_id
Definition: cel.h:173
const char * user_field
Definition: cel.h:175
const char * caller_id_ani
Definition: cel.h:161
const char * caller_id_name
Definition: cel.h:159
const char * event_name
Definition: cel.h:157
A structure to hold CEL global configuration options.
Definition: cel.h:230
int64_t events
Definition: cel.h:235
struct ao2_container * apps
Definition: cel.h:239
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
const ast_string_field tenantid
const ast_string_field accountcode
const ast_string_field userfield
const ast_string_field uniqueid
const ast_string_field name
const ast_string_field number
const ast_string_field rdnis
const ast_string_field ani
const ast_string_field name
const ast_string_field dnid
const ast_string_field data
const ast_string_field context
const ast_string_field exten
const ast_string_field appl
Structure representing a change of snapshot of channel state.
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_dialplan * dialplan
struct ast_channel_snapshot_peer * peer
struct ast_channel_snapshot_base * base
enum ast_channel_state state
struct ast_channel_snapshot_caller * caller
struct ast_flags flags
struct ast_channel_snapshot_hangup * hangup
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
An event.
Definition: event.c:81
Abstract JSON element (object, array, string, int, ...).
A multi channel blob data structure for multi_channel_blob stasis messages.
struct ast_json * blob
A parked call message payload.
Definition: parking.h:59
const ast_string_field parkinglot
Definition: parking.h:69
struct ast_channel_snapshot * retriever
Definition: parking.h:61
struct ast_channel_snapshot * parkee
Definition: parking.h:60
enum ast_parked_call_event_type event_type
Definition: parking.h:62
const ast_string_field parker_dial_string
Definition: parking.h:69
struct ast_party_id id
Caller party ID.
Definition: channel.h:422
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:429
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
struct ast_party_dialed::@213 number
Dialed/Called number.
struct ast_party_name name
Subscriber name.
Definition: channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:281
char * str
Subscriber name (Malloced)
Definition: channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:299
char * str
Subscriber phone number (Malloced)
Definition: channel.h:293
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:529
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
the list of registered channel types
Definition: channel.c:124
ast_cel_backend_cb callback
Definition: cel.c:350
char name[0]
Definition: cel.c:351
A container that holds all config-related information.
Definition: cel_custom.c:52
struct ast_cel_general_config * general
Definition: cel.c:229
char dialstatus[0]
Definition: cel.c:195
char uniqueid[AST_MAX_UNIQUEID]
Definition: cel.c:193
unsigned int count
Definition: cel.c:183
char id[0]
Definition: cel.c:185
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:978
#define ast_assert(a)
Definition: utils.h:776
#define ARRAY_LEN(a)
Definition: utils.h:703