Asterisk - The Open Source Telephony Project  21.4.1
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"
47 #include "asterisk/linkedlists.h"
48 #include "asterisk/utils.h"
49 #include "asterisk/config.h"
51 #include "asterisk/cli.h"
52 #include "asterisk/astobj2.h"
53 #include "asterisk/stasis_message_router.h"
54 #include "asterisk/stasis_channels.h"
55 #include "asterisk/stasis_bridges.h"
56 #include "asterisk/bridge.h"
57 #include "asterisk/parking.h"
58 #include "asterisk/pickup.h"
59 #include "asterisk/core_local.h"
60 #include "asterisk/taskprocessor.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 */
118 static 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 
135 struct stasis_message_type *cel_generic_type(void);
136 STASIS_MESSAGE_TYPE_DEFN(cel_generic_type);
137 
138 /*! Container for CEL backend information */
139 static 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 */
145 static 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 
163 struct cel_linkedid {
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. */
171 static 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 */
181 static 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 {
191  RAII_VAR(struct ast_cel_general_config *, cfg, NULL, ao2_cleanup);
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 */
210 struct cel_config {
211  struct ast_cel_general_config *general;
212 };
213 
214 
215 static AO2_GLOBAL_OBJ_STATIC(cel_configs);
216 
217 /*! \brief Destructor for cel_config */
218 static void cel_config_dtor(void *obj)
219 {
220  struct cel_config *cfg = obj;
221  ao2_cleanup(cfg->general);
222  cfg->general = NULL;
223 }
224 
225 static 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 */
242 static 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. */
251 static const char *ignore_categories[] = {
252  "manager",
253  "radius",
254  NULL,
255 };
256 
257 static 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. */
265 static 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 
270 static int cel_pre_apply_config(void);
271 
272 CONFIG_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 
277 static 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 
301 static struct aco_type *general_options[] = ACO_TYPES(&general_option);
302 
303 /*!
304  * \brief Map of ast_cel_event_type to strings
305  */
306 static 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 
328 struct cel_backend {
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 */
343 AO2_STRING_FIELD_CMP_FN(cel_dialstatus, uniqueid)
344 
345 unsigned 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 
355 static 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);
359  RAII_VAR(struct ao2_container *, backends, ao2_global_obj_ref(cel_backends), 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 
393  name = ast_cel_get_type_name(i);
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  }
403  ao2_iterator_destroy(&iter);
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  }
412  ao2_iterator_destroy(&iter);
413  }
414 
415  return CLI_SUCCESS;
416 }
417 
418 static 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);
431  return AST_CEL_INVALID_VALUE;
432 }
433 
434 static int ast_cel_track_event(enum ast_cel_event_type et)
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 
445 static 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 
474 static 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 
498 static 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 
517 static 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  }
561 }
562 
563 static int cel_backend_send_cb(void *obj, void *arg, int flags)
564 {
565  struct cel_backend *backend = obj;
566 
567  backend->callback(arg);
568  return 0;
569 }
570 
571 static int cel_report_event(struct ast_channel_snapshot *snapshot,
572  enum ast_cel_event_type event_type, const struct timeval *event_time,
573  const char *userdefevname, struct ast_json *extra,
574  const char *peer_str)
575 {
576  struct ast_event *ev;
577  RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
578  RAII_VAR(struct ao2_container *, backends, ao2_global_obj_ref(cel_backends), ao2_cleanup);
579 
580  if (!cfg || !cfg->general || !cfg->general->enable || !backends) {
581  return 0;
582  }
583 
584  /* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
585  * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
586  if (event_type == AST_CEL_CHANNEL_START
587  && ast_cel_track_event(AST_CEL_LINKEDID_END)) {
588  if (cel_linkedid_ref(snapshot->peer->linkedid)) {
589  return -1;
590  }
591  }
592 
593  if (!ast_cel_track_event(event_type)) {
594  return 0;
595  }
596 
597  if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
598  && !cel_track_app(snapshot->dialplan->appl)) {
599  return 0;
600  }
601 
602  ev = ast_cel_create_event_with_time(snapshot, event_type, event_time, userdefevname, extra, peer_str);
603  if (!ev) {
604  return -1;
605  }
606 
607  /* Distribute event to backends */
608  ao2_callback(backends, OBJ_MULTIPLE | OBJ_NODATA, cel_backend_send_cb, ev);
609  ast_event_destroy(ev);
610 
611  return 0;
612 }
613 
614 /* called whenever a channel is destroyed or a linkedid is changed to
615  * potentially emit a CEL_LINKEDID_END event */
616 static void check_retire_linkedid(struct ast_channel_snapshot *snapshot, const struct timeval *event_time)
617 {
618  RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
619  struct cel_linkedid *lid;
620 
621  if (!linkedids || ast_strlen_zero(snapshot->peer->linkedid)) {
622  /* The CEL module is shutdown. Abort. */
623  return;
624  }
625 
626  ao2_lock(linkedids);
627 
628  lid = ao2_find(linkedids, (void *) snapshot->peer->linkedid, OBJ_SEARCH_KEY);
629  if (!lid) {
630  ao2_unlock(linkedids);
631 
632  /*
633  * The user may have done a reload to start tracking linkedids
634  * when a call was already in progress. This is an unusual kind
635  * of change to make after starting Asterisk.
636  */
637  ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n",
638  snapshot->peer->linkedid);
639  return;
640  }
641 
642  if (!--lid->count) {
643  /* No channels use this linkedid anymore. */
644  ao2_unlink(linkedids, lid);
645  ao2_unlock(linkedids);
646 
647  cel_report_event(snapshot, AST_CEL_LINKEDID_END, event_time, NULL, NULL, NULL);
648  } else {
649  ao2_unlock(linkedids);
650  }
651  ao2_ref(lid, -1);
652 }
653 
654 /* Note that no 'chan_fixup' function is provided for this datastore type,
655  * because the channels that will use it will never be involved in masquerades.
656  */
657 static const struct ast_datastore_info fabricated_channel_datastore = {
658  .type = "CEL fabricated channel",
659  .destroy = ast_free_ptr,
660 };
661 
663 {
664  struct varshead *headp;
665  struct ast_var_t *newvariable;
666  const char *mixed_name;
667  char timebuf[30];
668  struct ast_channel *tchan;
669  struct ast_cel_event_record record = {
671  };
672  struct ast_datastore *datastore;
673  char *app_data;
674  RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
675 
676  if (!cfg || !cfg->general) {
677  return NULL;
678  }
679 
680  /* do not call ast_channel_alloc because this is not really a real channel */
681  if (!(tchan = ast_dummy_channel_alloc())) {
682  return NULL;
683  }
684 
685  headp = ast_channel_varshead(tchan);
686 
687  /* first, get the variables from the event */
688  if (ast_cel_fill_record(event, &record)) {
689  ast_channel_unref(tchan);
690  return NULL;
691  }
692 
693  /* next, fill the channel with their data */
694  mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
695  ? record.user_defined_name : record.event_name;
696  if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
697  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
698  }
699 
700  if (ast_strlen_zero(cfg->general->date_format)) {
701  snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
702  (long) record.event_time.tv_usec);
703  } else {
704  struct ast_tm tm;
705  ast_localtime(&record.event_time, &tm, NULL);
706  ast_strftime(timebuf, sizeof(timebuf), cfg->general->date_format, &tm);
707  }
708 
709  if ((newvariable = ast_var_assign("eventtime", timebuf))) {
710  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
711  }
712 
713  if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
714  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
715  }
716  if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
717  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
718  }
719  if ((newvariable = ast_var_assign("eventextra", record.extra))) {
720  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
721  }
722 
723  ast_channel_caller(tchan)->id.name.valid = 1;
724  ast_channel_caller(tchan)->id.name.str = ast_strdup(record.caller_id_name);
725  ast_channel_caller(tchan)->id.number.valid = 1;
726  ast_channel_caller(tchan)->id.number.str = ast_strdup(record.caller_id_num);
727  ast_channel_caller(tchan)->ani.number.valid = 1;
728  ast_channel_caller(tchan)->ani.number.str = ast_strdup(record.caller_id_ani);
729  ast_channel_redirecting(tchan)->from.number.valid = 1;
730  ast_channel_redirecting(tchan)->from.number.str = ast_strdup(record.caller_id_rdnis);
731  ast_channel_dialed(tchan)->number.str = ast_strdup(record.caller_id_dnid);
732 
733  ast_channel_exten_set(tchan, record.extension);
734  ast_channel_context_set(tchan, record.context);
735  ast_channel_name_set(tchan, record.channel_name);
736  ast_channel_internal_set_fake_ids(tchan, record.unique_id, record.linked_id);
737  ast_channel_accountcode_set(tchan, record.account_code);
738  ast_channel_peeraccount_set(tchan, record.peer_account);
739  ast_channel_userfield_set(tchan, record.user_field);
740 
741  if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
742  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
743  }
744 
745  ast_channel_amaflags_set(tchan, record.amaflag);
746 
747  /* We need to store an 'application name' and 'application
748  * data' on the channel for logging purposes, but the channel
749  * structure only provides a place to store pointers, and it
750  * expects these pointers to be pointing to data that does not
751  * need to be freed. This means that the channel's destructor
752  * does not attempt to free any storage that these pointers
753  * point to. However, we can't provide data in that form directly for
754  * these structure members. In order to ensure that these data
755  * elements have a lifetime that matches the channel's
756  * lifetime, we'll put them in a datastore attached to the
757  * channel, and set's the channel's pointers to point into the
758  * datastore. The datastore will then be automatically destroyed
759  * when the channel is destroyed.
760  */
761 
762  if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) {
763  ast_channel_unref(tchan);
764  return NULL;
765  }
766 
767  if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
768  ast_datastore_free(datastore);
769  ast_channel_unref(tchan);
770  return NULL;
771  }
772 
773  ast_channel_appl_set(tchan, strcpy(app_data, record.application_name));
774  ast_channel_data_set(tchan, strcpy(app_data + strlen(record.application_name) + 1,
775  record.application_data));
776 
777  datastore->data = app_data;
778  ast_channel_datastore_add(tchan, datastore);
779 
780  return tchan;
781 }
782 
783 static int cel_linkedid_ref(const char *linkedid)
784 {
785  RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
786  struct cel_linkedid *lid;
787 
788  if (ast_strlen_zero(linkedid)) {
789  ast_log(LOG_ERROR, "The linkedid should never be empty\n");
790  return -1;
791  }
792  if (!linkedids) {
793  /* The CEL module is shutdown. Abort. */
794  return -1;
795  }
796 
797  ao2_lock(linkedids);
798  lid = ao2_find(linkedids, (void *) linkedid, OBJ_SEARCH_KEY);
799  if (!lid) {
800  /*
801  * Changes to the lid->count member are protected by the
802  * container lock so the lid object does not need its own lock.
803  */
804  lid = ao2_alloc_options(sizeof(*lid) + strlen(linkedid) + 1, NULL,
806  if (!lid) {
807  ao2_unlock(linkedids);
808  return -1;
809  }
810  strcpy(lid->id, linkedid);/* Safe */
811 
812  ao2_link(linkedids, lid);
813  }
814  ++lid->count;
815  ao2_unlock(linkedids);
816  ao2_ref(lid, -1);
817 
818  return 0;
819 }
820 
821 int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *r)
822 {
824  ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record. "
825  "Please ensure all modules were compiled for "
826  "this version of Asterisk.\n");
827  return -1;
828  }
829 
831 
832  r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
833  r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
834 
835  r->event_name = ast_cel_get_type_name(r->event_type);
836  if (r->event_type == AST_CEL_USER_DEFINED) {
837  r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
838  } else {
839  r->user_defined_name = "";
840  }
841 
842  r->caller_id_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
843  r->caller_id_num = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
844  r->caller_id_ani = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
845  r->caller_id_rdnis = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDRDNIS), "");
846  r->caller_id_dnid = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDDNID), "");
847  r->extension = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTEN), "");
848  r->context = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CONTEXT), "");
849  r->channel_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CHANNAME), "");
850  r->application_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPNAME), "");
851  r->application_data = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPDATA), "");
852  r->account_code = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
853  r->peer_account = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEERACCT), "");
854  r->unique_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
855  r->linked_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
857  r->user_field = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
860 
861  return 0;
862 }
863 
864 /*! \brief Typedef for callbacks that get called on channel snapshot updates */
866  struct ast_channel_snapshot *old_snapshot,
867  struct ast_channel_snapshot *new_snapshot,
868  const struct timeval *event_time);
869 
870 static struct cel_dialstatus *get_dialstatus(const char *uniqueid)
871 {
872  struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
873  struct cel_dialstatus *dialstatus = NULL;
874 
875  if (dial_statuses) {
876  dialstatus = ao2_find(dial_statuses, uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK);
877  ao2_ref(dial_statuses, -1);
878  }
879  return dialstatus;
880 }
881 
882 static const char *get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
883 {
884  struct ast_json *json = ast_multi_channel_blob_get_json(blob);
885  if (!json) {
886  return NULL;
887  }
888 
889  json = ast_json_object_get(json, varname);
890  if (!json) {
891  return NULL;
892  }
893 
894  return ast_json_string_get(json);
895 }
896 
897 /*! \brief Handle channel state changes */
899  struct ast_channel_snapshot *old_snapshot,
900  struct ast_channel_snapshot *new_snapshot,
901  const struct timeval *event_time)
902 {
903  int is_hungup, was_hungup;
904 
905  if (!old_snapshot) {
906  cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, event_time, NULL, NULL, NULL);
907  return;
908  }
909 
910  was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
911  is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
912 
913  if (!was_hungup && is_hungup) {
914  struct ast_json *extra;
915  struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->base->uniqueid);
916 
917  extra = ast_json_pack("{s: i, s: s, s: s}",
918  "hangupcause", new_snapshot->hangup->cause,
919  "hangupsource", new_snapshot->hangup->source,
920  "dialstatus", dialstatus ? dialstatus->dialstatus : "");
921  cel_report_event(new_snapshot, AST_CEL_HANGUP, event_time, NULL, extra, NULL);
922  ast_json_unref(extra);
923  ao2_cleanup(dialstatus);
924 
925  cel_report_event(new_snapshot, AST_CEL_CHANNEL_END, event_time, NULL, NULL, NULL);
926  if (ast_cel_track_event(AST_CEL_LINKEDID_END)) {
927  check_retire_linkedid(new_snapshot, event_time);
928  }
929  return;
930  }
931 
932  if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
933  cel_report_event(new_snapshot, AST_CEL_ANSWER, event_time, NULL, NULL, NULL);
934  return;
935  }
936 }
937 
938 static void cel_channel_linkedid_change(
939  struct ast_channel_snapshot *old_snapshot,
940  struct ast_channel_snapshot *new_snapshot,
941  const struct timeval *event_time)
942 {
943  if (!old_snapshot) {
944  return;
945  }
946 
947  ast_assert(!ast_strlen_zero(new_snapshot->peer->linkedid));
948  ast_assert(!ast_strlen_zero(old_snapshot->peer->linkedid));
949 
950  if (ast_cel_track_event(AST_CEL_LINKEDID_END)
951  && strcmp(old_snapshot->peer->linkedid, new_snapshot->peer->linkedid)) {
952  cel_linkedid_ref(new_snapshot->peer->linkedid);
953  check_retire_linkedid(old_snapshot, event_time);
954  }
955 }
956 
957 static void cel_channel_app_change(
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 && !strcmp(old_snapshot->dialplan->appl, new_snapshot->dialplan->appl)) {
963  return;
964  }
965 
966  /* old snapshot has an application, end it */
967  if (old_snapshot && !ast_strlen_zero(old_snapshot->dialplan->appl)) {
968  cel_report_event(old_snapshot, AST_CEL_APP_END, event_time, NULL, NULL, NULL);
969  }
970 
971  /* new snapshot has an application, start it */
972  if (!ast_strlen_zero(new_snapshot->dialplan->appl)) {
973  cel_report_event(new_snapshot, AST_CEL_APP_START, event_time, NULL, NULL, NULL);
974  }
975 }
976 
977 /*! \brief Handlers for channel snapshot changes.
978  * \note Order of the handlers matters. Application changes must come before state
979  * changes to ensure that hangup notifications occur after application changes.
980  * Linkedid checking should always come last.
981  */
983  cel_channel_app_change,
985  cel_channel_linkedid_change,
986 };
987 
988 static int cel_filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
989 {
990  if (!snapshot) {
991  return 0;
992  }
993  return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
994 }
995 
996 static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
997  struct stasis_message *message)
998 {
999  struct ast_channel_snapshot_update *update = stasis_message_data(message);
1000  size_t i;
1001 
1002  if (cel_filter_channel_snapshot(update->old_snapshot) || cel_filter_channel_snapshot(update->new_snapshot)) {
1003  return;
1004  }
1005 
1006  for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {
1007  cel_channel_monitors[i](update->old_snapshot, update->new_snapshot, stasis_message_timestamp(message));
1008  }
1009 }
1010 
1011 static struct ast_str *cel_generate_peer_str(
1012  struct ast_bridge_snapshot *bridge,
1013  struct ast_channel_snapshot *chan)
1014 {
1015  struct ast_str *peer_str = ast_str_create(32);
1016  struct ao2_iterator i;
1017  char *current_chan = NULL;
1018 
1019  if (!peer_str) {
1020  return NULL;
1021  }
1022 
1023  for (i = ao2_iterator_init(bridge->channels, 0);
1024  (current_chan = ao2_iterator_next(&i));
1025  ao2_cleanup(current_chan)) {
1026  struct ast_channel_snapshot *current_snapshot;
1027 
1028  /* Don't add the channel for which this message is being generated */
1029  if (!strcmp(current_chan, chan->base->uniqueid)) {
1030  continue;
1031  }
1032 
1033  current_snapshot = ast_channel_snapshot_get_latest(current_chan);
1034  if (!current_snapshot) {
1035  continue;
1036  }
1037 
1038  ast_str_append(&peer_str, 0, "%s,", current_snapshot->base->name);
1039  ao2_cleanup(current_snapshot);
1040  }
1042 
1043  /* Rip off the trailing comma */
1044  ast_str_truncate(peer_str, -1);
1045 
1046  return peer_str;
1047 }
1048 
1049 static void cel_bridge_enter_cb(
1050  void *data, struct stasis_subscription *sub,
1051  struct stasis_message *message)
1052 {
1053  struct ast_bridge_blob *blob = stasis_message_data(message);
1054  struct ast_bridge_snapshot *snapshot = blob->bridge;
1055  struct ast_channel_snapshot *chan_snapshot = blob->channel;
1056  RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1057  RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
1058 
1059  if (cel_filter_channel_snapshot(chan_snapshot)) {
1060  return;
1061  }
1062 
1063  extra = ast_json_pack("{s: s, s: s}",
1064  "bridge_id", snapshot->uniqueid,
1065  "bridge_technology", snapshot->technology);
1066  if (!extra) {
1067  return;
1068  }
1069 
1070  peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
1071  if (!peer_str) {
1072  return;
1073  }
1074 
1075  cel_report_event(chan_snapshot, AST_CEL_BRIDGE_ENTER, stasis_message_timestamp(message),
1076  NULL, extra, ast_str_buffer(peer_str));
1077 }
1078 
1079 static void cel_bridge_leave_cb(
1080  void *data, struct stasis_subscription *sub,
1081  struct stasis_message *message)
1082 {
1083  struct ast_bridge_blob *blob = stasis_message_data(message);
1084  struct ast_bridge_snapshot *snapshot = blob->bridge;
1085  struct ast_channel_snapshot *chan_snapshot = blob->channel;
1086  RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1087  RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
1088 
1089  if (cel_filter_channel_snapshot(chan_snapshot)) {
1090  return;
1091  }
1092 
1093  extra = ast_json_pack("{s: s, s: s}",
1094  "bridge_id", snapshot->uniqueid,
1095  "bridge_technology", snapshot->technology);
1096  if (!extra) {
1097  return;
1098  }
1099 
1100  peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
1101  if (!peer_str) {
1102  return;
1103  }
1104 
1105  cel_report_event(chan_snapshot, AST_CEL_BRIDGE_EXIT, stasis_message_timestamp(message),
1106  NULL, extra, ast_str_buffer(peer_str));
1107 }
1108 
1109 static void cel_parking_cb(
1110  void *data, struct stasis_subscription *sub,
1111  struct stasis_message *message)
1112 {
1113  struct ast_parked_call_payload *parked_payload = stasis_message_data(message);
1114  RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
1115  const char *reason = NULL;
1116 
1117  switch (parked_payload->event_type) {
1118  case PARKED_CALL:
1119  extra = ast_json_pack("{s: s, s: s}",
1120  "parker_dial_string", parked_payload->parker_dial_string,
1121  "parking_lot", parked_payload->parkinglot);
1122  if (extra) {
1123  cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, stasis_message_timestamp(message),
1124  NULL, extra, NULL);
1125  }
1126  return;
1127  case PARKED_CALL_TIMEOUT:
1128  reason = "ParkedCallTimeOut";
1129  break;
1130  case PARKED_CALL_GIVEUP:
1131  reason = "ParkedCallGiveUp";
1132  break;
1133  case PARKED_CALL_UNPARKED:
1134  reason = "ParkedCallUnparked";
1135  break;
1136  case PARKED_CALL_FAILED:
1137  reason = "ParkedCallFailed";
1138  break;
1139  case PARKED_CALL_SWAP:
1140  reason = "ParkedCallSwap";
1141  break;
1142  }
1143 
1144  if (parked_payload->retriever) {
1145  extra = ast_json_pack("{s: s, s: s}",
1146  "reason", reason ?: "",
1147  "retriever", parked_payload->retriever->base->name);
1148  } else {
1149  extra = ast_json_pack("{s: s}", "reason", reason ?: "");
1150  }
1151 
1152  if (extra) {
1153  cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, stasis_message_timestamp(message),
1154  NULL, extra, NULL);
1155  }
1156 }
1157 
1158 static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_channel_snapshot *snapshot)
1159 {
1160  struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
1161  const char *dialstatus_string = get_blob_variable(blob, "dialstatus");
1162  struct cel_dialstatus *dialstatus;
1163  size_t dialstatus_string_len;
1164 
1165  if (!dial_statuses || ast_strlen_zero(dialstatus_string)) {
1166  ao2_cleanup(dial_statuses);
1167  return;
1168  }
1169 
1170  dialstatus = ao2_find(dial_statuses, snapshot->base->uniqueid, OBJ_SEARCH_KEY);
1171  if (dialstatus) {
1172  if (!strcasecmp(dialstatus_string, "ANSWER") && strcasecmp(dialstatus->dialstatus, "ANSWER")) {
1173  /* In the case of an answer after we already have a dial status we give
1174  * priority to the answer since the call was, well, answered. In the case of
1175  * failure dial status results we simply let the first failure be the status.
1176  */
1177  ao2_unlink(dial_statuses, dialstatus);
1178  ao2_ref(dialstatus, -1);
1179  } else {
1180  ao2_ref(dialstatus, -1);
1181  ao2_ref(dial_statuses, -1);
1182  return;
1183  }
1184  }
1185 
1186  dialstatus_string_len = strlen(dialstatus_string) + 1;
1187  dialstatus = ao2_alloc_options(sizeof(*dialstatus) + dialstatus_string_len, NULL,
1189  if (!dialstatus) {
1190  ao2_ref(dial_statuses, -1);
1191  return;
1192  }
1193 
1194  ast_copy_string(dialstatus->uniqueid, snapshot->base->uniqueid, sizeof(dialstatus->uniqueid));
1195  ast_copy_string(dialstatus->dialstatus, dialstatus_string, dialstatus_string_len);
1196 
1197  ao2_link(dial_statuses, dialstatus);
1198  ao2_ref(dialstatus, -1);
1199  ao2_ref(dial_statuses, -1);
1200 }
1201 
1202 static int is_valid_dialstatus(struct ast_multi_channel_blob *blob)
1203 {
1204  const char *dialstatus = get_blob_variable(blob, "dialstatus");
1205  int res = 0;
1206 
1207  if (ast_strlen_zero(dialstatus)) {
1208  res = 0;
1209  } else if (!strcasecmp(dialstatus, "CHANUNAVAIL")) {
1210  res = 1;
1211  } else if (!strcasecmp(dialstatus, "CONGESTION")) {
1212  res = 1;
1213  } else if (!strcasecmp(dialstatus, "NOANSWER")) {
1214  res = 1;
1215  } else if (!strcasecmp(dialstatus, "BUSY")) {
1216  res = 1;
1217  } else if (!strcasecmp(dialstatus, "ANSWER")) {
1218  res = 1;
1219  } else if (!strcasecmp(dialstatus, "CANCEL")) {
1220  res = 1;
1221  } else if (!strcasecmp(dialstatus, "DONTCALL")) {
1222  res = 1;
1223  } else if (!strcasecmp(dialstatus, "TORTURE")) {
1224  res = 1;
1225  } else if (!strcasecmp(dialstatus, "INVALIDARGS")) {
1226  res = 1;
1227  }
1228  return res;
1229 }
1230 
1231 static void cel_dial_cb(void *data, struct stasis_subscription *sub,
1232  struct stasis_message *message)
1233 {
1234  struct ast_multi_channel_blob *blob = stasis_message_data(message);
1235  struct ast_channel_snapshot *snapshot;
1236 
1237  snapshot = ast_multi_channel_blob_get_channel(blob, "caller");
1238  if (!snapshot || cel_filter_channel_snapshot(snapshot)) {
1239  return;
1240  }
1241 
1242  if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
1243  struct ast_json *extra;
1244 
1245  extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
1246  if (extra) {
1247  cel_report_event(snapshot, AST_CEL_FORWARD, stasis_message_timestamp(message),
1248  NULL, extra, NULL);
1249  ast_json_unref(extra);
1250  }
1251  }
1252 
1253  if (is_valid_dialstatus(blob)) {
1254  save_dialstatus(blob, snapshot);
1255  }
1256 }
1257 
1258 static void cel_generic_cb(
1259  void *data, struct stasis_subscription *sub,
1260  struct stasis_message *message)
1261 {
1262  struct ast_channel_blob *obj = stasis_message_data(message);
1263  int event_type = ast_json_integer_get(ast_json_object_get(obj->blob, "event_type"));
1264  struct ast_json *event_details = ast_json_object_get(obj->blob, "event_details");
1265 
1266  switch (event_type) {
1267  case AST_CEL_USER_DEFINED:
1268  {
1269  const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
1270  struct ast_json *extra = ast_json_object_get(event_details, "extra");
1271  cel_report_event(obj->snapshot, event_type, stasis_message_timestamp(message),
1272  event, extra, NULL);
1273  break;
1274  }
1275  default:
1276  ast_log(LOG_ERROR, "Unhandled %s event blob\n", ast_cel_get_type_name(event_type));
1277  break;
1278  }
1279 }
1280 
1281 static void cel_blind_transfer_cb(
1282  void *data, struct stasis_subscription *sub,
1283  struct stasis_message *message)
1284 {
1285  struct ast_blind_transfer_message *transfer_msg = stasis_message_data(message);
1286  struct ast_channel_snapshot *chan_snapshot = transfer_msg->transferer;
1287  struct ast_bridge_snapshot *bridge_snapshot = transfer_msg->bridge;
1288  struct ast_json *extra;
1289 
1290  if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
1291  return;
1292  }
1293 
1294  extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
1295  "extension", transfer_msg->exten,
1296  "context", transfer_msg->context,
1297  "bridge_id", bridge_snapshot->uniqueid,
1298  "transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->base->name : "N/A",
1299  "transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->base->uniqueid : "N/A");
1300  if (extra) {
1301  cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, stasis_message_timestamp(message),
1302  NULL, extra, NULL);
1303  ast_json_unref(extra);
1304  }
1305 }
1306 
1307 static void cel_attended_transfer_cb(
1308  void *data, struct stasis_subscription *sub,
1309  struct stasis_message *message)
1310 {
1311  struct ast_attended_transfer_message *xfer = stasis_message_data(message);
1312  struct ast_json *extra = NULL;
1313  struct ast_bridge_snapshot *bridge1, *bridge2;
1314  struct ast_channel_snapshot *channel1, *channel2;
1315 
1316  /* Make sure bridge1 is always non-NULL */
1317  if (!xfer->to_transferee.bridge_snapshot) {
1318  bridge1 = xfer->to_transfer_target.bridge_snapshot;
1319  bridge2 = xfer->to_transferee.bridge_snapshot;
1320  channel1 = xfer->to_transfer_target.channel_snapshot;
1321  channel2 = xfer->to_transferee.channel_snapshot;
1322  } else {
1323  bridge1 = xfer->to_transferee.bridge_snapshot;
1324  bridge2 = xfer->to_transfer_target.bridge_snapshot;
1325  channel1 = xfer->to_transferee.channel_snapshot;
1326  channel2 = xfer->to_transfer_target.channel_snapshot;
1327  }
1328 
1329  switch (xfer->dest_type) {
1330  case AST_ATTENDED_TRANSFER_DEST_FAIL:
1331  return;
1332  /* handle these three the same */
1333  case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
1334  case AST_ATTENDED_TRANSFER_DEST_LINK:
1335  case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
1336  extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
1337  "bridge1_id", bridge1->uniqueid,
1338  "channel2_name", channel2->base->name,
1339  "channel2_uniqueid", channel2->base->uniqueid,
1340  "bridge2_id", bridge2->uniqueid,
1341  "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
1342  "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
1343  "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
1344  "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
1345  if (!extra) {
1346  return;
1347  }
1348  break;
1349  case AST_ATTENDED_TRANSFER_DEST_APP:
1350  case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
1351  extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
1352  "bridge1_id", bridge1->uniqueid,
1353  "channel2_name", channel2->base->name,
1354  "channel2_uniqueid", channel2->base->uniqueid,
1355  "app", xfer->dest.app,
1356  "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
1357  "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
1358  "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
1359  "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
1360  if (!extra) {
1361  return;
1362  }
1363  break;
1364  }
1365  cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, stasis_message_timestamp(message),
1366  NULL, extra, NULL);
1367  ast_json_unref(extra);
1368 }
1369 
1370 static void cel_pickup_cb(
1371  void *data, struct stasis_subscription *sub,
1372  struct stasis_message *message)
1373 {
1374  struct ast_multi_channel_blob *obj = stasis_message_data(message);
1375  struct ast_channel_snapshot *channel = ast_multi_channel_blob_get_channel(obj, "channel");
1376  struct ast_channel_snapshot *target = ast_multi_channel_blob_get_channel(obj, "target");
1377  struct ast_json *extra;
1378 
1379  if (!channel || !target) {
1380  return;
1381  }
1382 
1383  extra = ast_json_pack("{s: s, s: s}",
1384  "pickup_channel", channel->base->name,
1385  "pickup_channel_uniqueid", channel->base->uniqueid);
1386  if (!extra) {
1387  return;
1388  }
1389 
1390  cel_report_event(target, AST_CEL_PICKUP, stasis_message_timestamp(message), NULL, extra, NULL);
1391  ast_json_unref(extra);
1392 }
1393 
1394 
1395 static void cel_local_optimization_cb_helper(
1396  void *data, struct stasis_subscription *sub,
1397  struct stasis_message *message,
1398  enum ast_cel_event_type event_type)
1399 {
1400  struct ast_multi_channel_blob *obj = stasis_message_data(message);
1401  struct ast_channel_snapshot *localone = ast_multi_channel_blob_get_channel(obj, "1");
1402  struct ast_channel_snapshot *localtwo = ast_multi_channel_blob_get_channel(obj, "2");
1403  struct ast_json *extra;
1404 
1405  if (!localone || !localtwo) {
1406  return;
1407  }
1408 
1409  extra = ast_json_pack("{s: s, s: s}",
1410  "local_two", localtwo->base->name,
1411  "local_two_uniqueid", localtwo->base->uniqueid);
1412  if (!extra) {
1413  return;
1414  }
1415 
1416  cel_report_event(localone, event_type, stasis_message_timestamp(message), NULL, extra, NULL);
1417  ast_json_unref(extra);
1418 }
1419 
1420 static void cel_local_optimization_end_cb(
1421  void *data, struct stasis_subscription *sub,
1422  struct stasis_message *message)
1423 {
1424  /* The AST_CEL_LOCAL_OPTIMIZE event has always been triggered by the end of optimization.
1425  This can either be used as an indication that the call was locally optimized, or as
1426  the END event in combination with the subsequently added BEGIN event. */
1427  cel_local_optimization_cb_helper(data, sub, message, AST_CEL_LOCAL_OPTIMIZE);
1428 }
1429 
1430 static void cel_local_optimization_begin_cb(
1431  void *data, struct stasis_subscription *sub,
1432  struct stasis_message *message)
1433 {
1434  cel_local_optimization_cb_helper(data, sub, message, AST_CEL_LOCAL_OPTIMIZE_BEGIN);
1435 }
1436 
1437 static void destroy_routes(void)
1438 {
1440  cel_state_router = NULL;
1441 }
1442 
1443 static void destroy_subscriptions(void)
1444 {
1445  ao2_cleanup(cel_aggregation_topic);
1446  cel_aggregation_topic = NULL;
1447  ao2_cleanup(cel_topic);
1448  cel_topic = NULL;
1449 
1450  cel_channel_forwarder = stasis_forward_cancel(cel_channel_forwarder);
1451  cel_bridge_forwarder = stasis_forward_cancel(cel_bridge_forwarder);
1452  cel_parking_forwarder = stasis_forward_cancel(cel_parking_forwarder);
1453  cel_cel_forwarder = stasis_forward_cancel(cel_cel_forwarder);
1454 }
1455 
1456 static int unload_module(void)
1457 {
1458  destroy_routes();
1460  STASIS_MESSAGE_TYPE_CLEANUP(cel_generic_type);
1461 
1462  ast_cli_unregister(&cli_status);
1463  aco_info_destroy(&cel_cfg_info);
1464  ao2_global_obj_release(cel_configs);
1465  ao2_global_obj_release(cel_dialstatus_store);
1466  ao2_global_obj_release(cel_linkedids);
1467  ao2_global_obj_release(cel_backends);
1468 
1469  return 0;
1470 }
1471 
1472 /*!
1473  * \brief Create the Stasis subscriptions for CEL
1474  */
1475 static int create_subscriptions(void)
1476 {
1477  cel_aggregation_topic = stasis_topic_create("cel:aggregator");
1478  if (!cel_aggregation_topic) {
1479  return -1;
1480  }
1481 
1482  cel_topic = stasis_topic_create("cel:misc");
1483  if (!cel_topic) {
1484  return -1;
1485  }
1486 
1487  cel_channel_forwarder = stasis_forward_all(
1489  cel_aggregation_topic);
1490  if (!cel_channel_forwarder) {
1491  return -1;
1492  }
1493 
1494  cel_bridge_forwarder = stasis_forward_all(
1496  cel_aggregation_topic);
1497  if (!cel_bridge_forwarder) {
1498  return -1;
1499  }
1500 
1501  cel_parking_forwarder = stasis_forward_all(
1503  cel_aggregation_topic);
1504  if (!cel_parking_forwarder) {
1505  return -1;
1506  }
1507 
1508  cel_cel_forwarder = stasis_forward_all(
1509  ast_cel_topic(),
1510  cel_aggregation_topic);
1511  if (!cel_cel_forwarder) {
1512  return -1;
1513  }
1514 
1515  return 0;
1516 }
1517 
1518 /*!
1519  * \brief Create the Stasis message router and routes for CEL
1520  */
1521 static int create_routes(void)
1522 {
1523  int ret = 0;
1524 
1525  cel_state_router = stasis_message_router_create(cel_aggregation_topic);
1526  if (!cel_state_router) {
1527  return -1;
1528  }
1529  stasis_message_router_set_congestion_limits(cel_state_router, -1,
1531 
1532  ret |= stasis_message_router_add(cel_state_router,
1534  cel_snapshot_update_cb,
1535  NULL);
1536 
1537  ret |= stasis_message_router_add(cel_state_router,
1539  cel_dial_cb,
1540  NULL);
1541 
1542  ret |= stasis_message_router_add(cel_state_router,
1543  ast_channel_entered_bridge_type(),
1544  cel_bridge_enter_cb,
1545  NULL);
1546 
1547  ret |= stasis_message_router_add(cel_state_router,
1548  ast_channel_left_bridge_type(),
1549  cel_bridge_leave_cb,
1550  NULL);
1551 
1552  ret |= stasis_message_router_add(cel_state_router,
1554  cel_parking_cb,
1555  NULL);
1556 
1557  ret |= stasis_message_router_add(cel_state_router,
1558  cel_generic_type(),
1559  cel_generic_cb,
1560  NULL);
1561 
1562  ret |= stasis_message_router_add(cel_state_router,
1563  ast_blind_transfer_type(),
1564  cel_blind_transfer_cb,
1565  NULL);
1566 
1567  ret |= stasis_message_router_add(cel_state_router,
1568  ast_attended_transfer_type(),
1569  cel_attended_transfer_cb,
1570  NULL);
1571 
1572  ret |= stasis_message_router_add(cel_state_router,
1574  cel_pickup_cb,
1575  NULL);
1576 
1577  ret |= stasis_message_router_add(cel_state_router,
1579  cel_local_optimization_end_cb,
1580  NULL);
1581 
1582  ret |= stasis_message_router_add(cel_state_router,
1584  cel_local_optimization_begin_cb,
1585  NULL);
1586 
1587  if (ret) {
1588  ast_log(AST_LOG_ERROR, "Failed to register for Stasis messages\n");
1589  }
1590 
1591  return ret;
1592 }
1593 
1596 
1597 static int load_module(void)
1598 {
1599  struct ao2_container *container;
1600 
1602  NUM_APP_BUCKETS, cel_linkedid_hash_fn, NULL, cel_linkedid_cmp_fn);
1603  ao2_global_obj_replace_unref(cel_linkedids, container);
1604  ao2_cleanup(container);
1605  if (!container) {
1606  return AST_MODULE_LOAD_FAILURE;
1607  }
1608 
1610  NUM_DIALSTATUS_BUCKETS, cel_dialstatus_hash_fn, NULL, cel_dialstatus_cmp_fn);
1611  ao2_global_obj_replace_unref(cel_dialstatus_store, container);
1612  ao2_cleanup(container);
1613  if (!container) {
1614  return AST_MODULE_LOAD_FAILURE;
1615  }
1616 
1617  if (STASIS_MESSAGE_TYPE_INIT(cel_generic_type)) {
1618  return AST_MODULE_LOAD_FAILURE;
1619  }
1620 
1621  if (ast_cli_register(&cli_status)) {
1622  return AST_MODULE_LOAD_FAILURE;
1623  }
1624 
1626  cel_backend_hash_fn, NULL, cel_backend_cmp_fn);
1627  ao2_global_obj_replace_unref(cel_backends, container);
1628  ao2_cleanup(container);
1629  if (!container) {
1630  return AST_MODULE_LOAD_FAILURE;
1631  }
1632 
1633  if (aco_info_init(&cel_cfg_info)) {
1634  return AST_MODULE_LOAD_FAILURE;
1635  }
1636 
1637  aco_option_register(&cel_cfg_info, "enable", ACO_EXACT, general_options, "no", OPT_BOOL_T, 1, FLDSET(struct ast_cel_general_config, enable));
1638  aco_option_register(&cel_cfg_info, "dateformat", ACO_EXACT, general_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_cel_general_config, date_format));
1639  aco_option_register_custom(&cel_cfg_info, "apps", ACO_EXACT, general_options, "", apps_handler, 0);
1640  aco_option_register_custom(&cel_cfg_info, "events", ACO_EXACT, general_options, "", events_handler, 0);
1641 
1642  if (aco_process_config(&cel_cfg_info, 0)) {
1643  struct cel_config *cel_cfg = cel_config_alloc();
1644 
1645  if (!cel_cfg) {
1646  return AST_MODULE_LOAD_FAILURE;
1647  }
1648 
1649  /* We couldn't process the configuration so create a default config. */
1650  if (!aco_set_defaults(&general_option, "general", cel_cfg->general)) {
1651  ast_log(LOG_NOTICE, "Failed to process CEL configuration; using defaults\n");
1652  ao2_global_obj_replace_unref(cel_configs, cel_cfg);
1653  }
1654  ao2_ref(cel_cfg, -1);
1655  }
1656 
1657  if (create_subscriptions()) {
1658  return AST_MODULE_LOAD_FAILURE;
1659  }
1660 
1661  if (ast_cel_check_enabled() && create_routes()) {
1662  return AST_MODULE_LOAD_FAILURE;
1663  }
1664 
1665  return AST_MODULE_LOAD_SUCCESS;
1666 }
1667 
1668 static int reload_module(void)
1669 {
1670  unsigned int was_enabled = ast_cel_check_enabled();
1671  unsigned int is_enabled;
1672 
1673  if (aco_process_config(&cel_cfg_info, 1) == ACO_PROCESS_ERROR) {
1674  return -1;
1675  }
1676 
1677  is_enabled = ast_cel_check_enabled();
1678 
1679  if (!was_enabled && is_enabled) {
1680  if (create_routes()) {
1681  return -1;
1682  }
1683  } else if (was_enabled && !is_enabled) {
1684  destroy_routes();
1685  }
1686 
1687  ast_verb(3, "CEL logging %sabled.\n", is_enabled ? "en" : "dis");
1688 
1689  return 0;
1690 }
1691 
1693  const char *event,
1694  const char *extra)
1695 {
1696  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1697 
1698  blob = ast_json_pack("{s: s, s: {s: s}}",
1699  "event", event,
1700  "extra", "extra", S_OR(extra, ""));
1701  if (!blob) {
1702  return;
1703  }
1705 }
1706 
1708  enum ast_cel_event_type event_type,
1709  struct ast_json *blob)
1710 {
1711  struct ast_json *cel_blob;
1712  struct stasis_message *message;
1713 
1714  cel_blob = ast_json_pack("{s: i, s: o}",
1715  "event_type", event_type,
1716  "event_details", ast_json_ref(blob));
1717 
1718  message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), cel_generic_type(), cel_blob);
1719  if (message) {
1720  stasis_publish(ast_cel_topic(), message);
1721  }
1722  ao2_cleanup(message);
1723  ast_json_unref(cel_blob);
1724 }
1725 
1727 {
1728  return cel_topic;
1729 }
1730 
1732 {
1733  RAII_VAR(struct cel_config *, mod_cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
1734 
1735  if (!mod_cfg || !mod_cfg->general) {
1736  return NULL;
1737  }
1738 
1739  ao2_ref(mod_cfg->general, +1);
1740  return mod_cfg->general;
1741 }
1742 
1744 {
1745  int was_enabled;
1746  int is_enabled;
1747  struct ast_cel_general_config *cleanup_config;
1748  struct cel_config *mod_cfg = ao2_global_obj_ref(cel_configs);
1749 
1750  if (mod_cfg) {
1751  was_enabled = ast_cel_check_enabled();
1752 
1753  cleanup_config = mod_cfg->general;
1754  ao2_bump(config);
1755  mod_cfg->general = config;
1756  ao2_cleanup(cleanup_config);
1757 
1758  is_enabled = ast_cel_check_enabled();
1759  if (!was_enabled && is_enabled) {
1760  create_routes();
1761  } else if (was_enabled && !is_enabled) {
1762  destroy_routes();
1763  }
1764 
1765  ao2_ref(mod_cfg, -1);
1766  }
1767 }
1768 
1769 int ast_cel_backend_unregister(const char *name)
1770 {
1771  struct ao2_container *backends = ao2_global_obj_ref(cel_backends);
1772 
1773  if (backends) {
1774  ao2_find(backends, name, OBJ_SEARCH_KEY | OBJ_NODATA | OBJ_UNLINK);
1775  ao2_ref(backends, -1);
1776  }
1777 
1778  return 0;
1779 }
1780 
1781 int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
1782 {
1783  RAII_VAR(struct ao2_container *, backends, ao2_global_obj_ref(cel_backends), ao2_cleanup);
1784  struct cel_backend *backend;
1785 
1786  if (!backends || ast_strlen_zero(name) || !backend_callback) {
1787  return -1;
1788  }
1789 
1790  /* The backend object is immutable so it doesn't need a lock of its own. */
1791  backend = ao2_alloc_options(sizeof(*backend) + 1 + strlen(name), NULL,
1793  if (!backend) {
1794  return -1;
1795  }
1796  strcpy(backend->name, name);/* Safe */
1797  backend->callback = backend_callback;
1798 
1799  ao2_link(backends, backend);
1800  ao2_ref(backend, -1);
1801  return 0;
1802 }
1803 
1804 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "CEL Engine",
1805  .support_level = AST_MODULE_SUPPORT_CORE,
1806  .load = load_module,
1807  .unload = unload_module,
1808  .reload = reload_module,
1809  .load_pri = AST_MODPRI_CORE,
1810  .requires = "extconfig",
1811 );
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
const char * type
Definition: datastore.h:32
cel_channel_snapshot_monitor cel_channel_monitors[]
Handlers for channel snapshot changes.
Definition: cel.c:982
the last channel with the given linkedid is retired
Definition: cel.h:71
#define NUM_APP_BUCKETS
Number of buckets for the appset container.
Definition: cel.c:156
const ast_string_field data
Helper struct for getting the fields out of a CEL event.
Definition: cel.h:138
Channel Event CID name Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:157
Channel Event app name Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:187
struct ao2_container * channels
Definition: bridge.h:331
Main Channel structure associated with a channel.
Local proxy channel special access.
#define CEL_MAX_EVENT_IDS
Maximum possible CEL event IDs.
Definition: cel.c:151
An event.
Definition: event.c:81
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
static void cel_config_dtor(void *obj)
Destructor for cel_config.
Definition: cel.c:218
A container that holds all config-related information.
Definition: cel_custom.c:53
struct ast_channel_snapshot_base * base
static struct aco_file cel_conf
The config file to be processed for the module.
Definition: cel.c:265
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:971
Asterisk main include file. File version handling, generic pbx functions.
AO2_STRING_FIELD_HASH_FN(transport_monitor, key)
Hashing function for struct transport_monitor.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:386
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
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
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.
Message representing attended transfer.
struct ast_channel_snapshot * channel
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
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
Channel Event extra data Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:259
Call Parking API.
const ast_string_field name
#define BACKEND_BUCKETS
Definition: cel.c:142
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
Registered applications container.
Definition: pbx_app.c:67
static struct stasis_forward * cel_parking_forwarder
Definition: cel.c:130
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
char exten[AST_MAX_EXTENSION]
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.
Message published during a blind transfer.
Call Event Logging API.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_party_name name
Subscriber name.
Definition: channel.h:340
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:527
struct ast_json * blob
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
struct ast_channel_snapshot * snapshot
Call Pickup API.
int ast_cli_unregister(struct ast_cli_entry *e)
Unregisters a command or an array of commands.
Definition: main/cli.c:2432
descriptor for a cli entry.
Definition: cli.h:171
struct stasis_message_type * ast_parked_call_type(void)
accessor for the parked call stasis message type
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
Definition: taskprocessor.h:64
const ast_string_field rdnis
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1693
static struct stasis_topic * cel_aggregation_topic
Definition: cel.c:121
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
Structure that contains a snapshot of information about a bridge.
Definition: bridge.h:314
Channel Event channel name Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:181
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
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
A local channel optimization occurred, this marks the end.
Definition: cel.h:77
static void destroy_subscriptions(void)
Destroy the active Stasis subscriptions.
Definition: cdr.c:4369
Structure for variables, used for configurations and for channel variables.
Channel Event UniqueID Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:211
Channel Event context name Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:175
Structure representing a snapshot of channel state.
Channel Event app args/data Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:193
void * ast_cel_general_config_alloc(void)
Allocate a CEL configuration object.
Definition: cel.c:189
Channel Event peeraccount Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:253
Channel Event Time (micro-seconds) Used by: AST_EVENT_CEL Payload type: UINT.
Definition: event_defs.h:145
Channel Event CID dnid Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:235
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:810
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition: strings.h:1365
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
channel birth
Definition: cel.h:45
Structure for a data store type.
Definition: datastore.h:31
AO2_STRING_FIELD_CMP_FN(transport_monitor, key)
Comparison function for struct transport_monitor.
struct ast_channel_snapshot * target
const ast_string_field accountcode
char * str
Subscriber name (Malloced)
Definition: channel.h:264
Definition: astman.c:222
const ast_string_field uniqueid
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
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
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.
A local channel optimization has begun.
Definition: cel.h:79
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
CONFIG_INFO_CORE("stasis", cfg_info, globals, stasis_config_alloc,.files=ACO_FILES(&stasis_conf),)
Register information about the configs being processed by this module.
struct ast_cel_general_config * ast_cel_get_config(void)
Obtain the current CEL configuration.
Definition: cel.c:1731
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
A parked call message payload.
Definition: parking.h:59
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
Structure for a data store object.
Definition: datastore.h:64
static const char *const cel_event_types[CEL_MAX_EVENT_IDS]
Map of ast_cel_event_type to strings.
Definition: cel.c:306
static struct stasis_forward * cel_channel_forwarder
Definition: cel.c:124
The representation of a single configuration file to be processed.
Structure representing a change of snapshot of channel state.
enum aco_type_t type
enum ast_parked_call_event_type event_type
Definition: parking.h:62
void ast_free_ptr(void *ptr)
free() wrapper
Definition: main/astmm.c:1739
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
struct ast_channel_snapshot_dialplan * dialplan
struct ast_bridge_channel_snapshot_pair to_transferee
int64_t events
Definition: cel.h:228
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...
Channel Event Type Used by: AST_EVENT_CEL Payload type: UINT.
Definition: event_defs.h:133
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
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...
the list of registered channel types
Definition: channel.c:121
Utility functions.
Blob of data associated with a channel.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
Channel Event Time (seconds) Used by: AST_EVENT_CEL Payload type: UINT.
Definition: event_defs.h:139
#define ast_cli_register(e)
Registers a command or an array of commands.
Definition: cli.h:256
Channel Event CID num Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:163
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
struct ast_party_id id
Caller party ID.
Definition: channel.h:420
struct ast_bridge_channel_snapshot_pair to_transfer_target
const ast_string_field context
Configuration File Parser.
channel enters a bridge
Definition: cel.h:57
Channel Event extension name Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:169
struct ast_bridge_snapshot * bridge
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
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:865
const ast_string_field technology
Definition: bridge.h:328
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:427
struct ast_channel_snapshot * parkee
Definition: parking.h:60
General Asterisk PBX channel definitions.
void(* ast_cel_backend_cb)(struct ast_event *event)
CEL backend callback.
Definition: cel.h:310
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
const ast_string_field appl
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1282
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:662
struct ast_channel_snapshot * transferee
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
an app ends
Definition: cel.h:55
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
unsigned int ast_cel_check_enabled(void)
Hashing function for cel_backend.
Definition: cel.c:345
char dialstatus[0]
Definition: cel.c:177
static struct stasis_forward * cel_bridge_forwarder
Definition: cel.c:127
void ast_cel_publish_user_event(struct ast_channel *chan, const char *event, const char *extra)
Publish a CEL user event.
Definition: cel.c:1692
char uniqueid[AST_MAX_UNIQUEID]
Definition: cel.c:175
uint32_t version
struct ABI version
Definition: cel.h:148
const ast_string_field exten
struct ast_channel_snapshot_hangup * hangup
static struct stasis_rest_handlers events
REST handler for /api-docs/events.json.
Channel Event Userfield Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:217
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value)
A set of macros to manage forward-linked lists.
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
struct ao2_container * container
Definition: res_fax.c:501
struct ast_bridge_snapshot * bridge
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:898
hangup terminates connection
Definition: cel.h:49
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:617
Blob of data associated with a bridge.
Channel Event CID RDNIS field Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:229
enum aco_category_op category_match
a transfer occurs
Definition: cel.h:65
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition: strings.h:1321
Core PBX routines and definitions.
a channel is parked
Definition: cel.h:61
struct stasis_topic * ast_cel_topic(void)
Get the CEL topic.
Definition: cel.c:1726
Their was an error and no changes were applied.
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:1707
struct ast_channel_snapshot_caller * caller
enum ast_attended_transfer_dest_type dest_type
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
Definition: stasis.h:1440
Configuration option-handling.
struct stasis_message_type * ast_call_pickup_type(void)
accessor for call pickup message type
a transfer occurs
Definition: cel.h:67
struct ast_channel_snapshot * transferer
#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
Support for dynamic strings.
Definition: strings.h:623
const ast_string_field dnid
Channel Event User Event Name Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:151
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
Type for default option handler for bools (ast_true/ast_false)
void ast_cel_set_config(struct ast_cel_general_config *config)
Set the current CEL configuration.
Definition: cel.c:1743
char id[0]
Definition: cel.c:167
static struct stasis_message_router * cel_state_router
Definition: cel.c:115
static const char * ignore_categories[]
Definition: cel.c:251
char context[AST_MAX_CONTEXT]
const ast_string_field userfield
unsigned int count
Definition: cel.c:165
struct ao2_container * apps
Definition: cel.h:232
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
static int create_routes(void)
Create the Stasis message router and routes for CEL.
Definition: cel.c:1521
static struct stasis_topic * cel_topic
Definition: cel.c:118
channel end
Definition: cel.h:47
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511
char * command
Definition: cli.h:186
Channel Event Peer – for Things involving multiple channels, like BRIDGE Used by: AST_EVENT_CEL Payl...
Definition: event_defs.h:241
Channel Event CID ANI field Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:223
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
Module could not be loaded properly.
Definition: module.h:102
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Support for logging to various files, console and syslog Configuration in file logger.conf.
struct ast_channel_snapshot * new_snapshot
enum ast_channel_state state
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
const ast_string_field uniqueid
Definition: bridge.h:328
An API for managing task processing threads that can be shared across modules.
const ast_string_field parkinglot
Definition: parking.h:69
Channel Event AMA flags Used by: AST_EVENT_CEL Payload type: UINT.
Definition: event_defs.h:199
struct stasis_message_type * ast_channel_snapshot_type(void)
Message type for ast_channel_snapshot_update.
struct ast_channel_snapshot * old_snapshot
#define AST_CEL_EVENT_RECORD_VERSION
struct ABI version
Definition: cel.h:143
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.
const char * usage
Definition: cli.h:177
static int is_enabled(void)
Helper function to check if module is enabled.
Definition: res_ari.c:159
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:293
const ast_string_field ani
int ast_cel_backend_unregister(const char *name)
Unregister a CEL backend.
Definition: cel.c:1769
ast_cel_backend_cb callback
Definition: cel.c:329
#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
A structure to hold CEL global configuration options.
Definition: cel.h:223
void * data
Definition: datastore.h:66
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
struct stasis_topic * ast_parking_topic(void)
accessor for the parking stasis topic
Definition: parking.c:67
Channel Event LinkedID Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:247
void ast_event_destroy(struct ast_event *event)
Destroy an event.
Definition: event.c:524
#define NUM_DIALSTATUS_BUCKETS
Number of buckets for the dialstatus container.
Definition: cel.c:161
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...
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Standard Command Line Interface.
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
struct ast_event * ast_event_new(enum ast_event_type event_type,...)
Create a new event.
Definition: event.c:402
Type information about a category-level configurable object.
const ast_string_field number
static int enabled
Whether or not we are storing history.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#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
A ringing phone is answered.
Definition: cel.h:51
struct ast_flags flags
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.
const char * filename
A multi channel blob data structure for multi_channel_blob stasis messages.
static AO2_GLOBAL_OBJ_STATIC(cel_backends)
struct ast_party_dialed::@206 number
Dialed/Called number.
channel out of the park
Definition: cel.h:63
const ast_string_field parker_dial_string
Definition: parking.h:69
Abstract JSON element (object, array, string, int, ...).
Type for default option handler for stringfields.
a user-defined event, the event name field should be set
Definition: cel.h:69
channel exits a bridge
Definition: cel.h:59
static struct stasis_forward * cel_cel_forwarder
Definition: cel.c:133
ast_cel_event_type
CEL event types.
Definition: cel.h:41
Forwarding information.
Definition: stasis.c:1531
struct stasis_message_type * ast_channel_dial_type(void)
Message type for when a channel dials another channel.
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:821
Generic container type.
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
an app starts
Definition: cel.h:53
struct ast_channel_snapshot * transferee
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:1578
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:302
struct ast_channel_snapshot_peer * peer
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_channel_snapshot * retriever
Definition: parking.h:61
Bridging API.
Asterisk module definitions.
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:332
int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
Register a CEL backend.
Definition: cel.c:1781
#define AST_MAX_UNIQUEID
Definition: channel.h:168
#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
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
char name[0]
Definition: cel.c:330
a directed pickup was performed on this channel
Definition: cel.h:73
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
static void cel_general_config_dtor(void *obj)
Destructor for cel_config.
Definition: cel.c:181
enum ast_transfer_result result
this call was forwarded somewhere else
Definition: cel.h:75
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static int create_subscriptions(void)
Create the Stasis subscriptions for CEL.
Definition: cel.c:1475
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
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
Channel Event AccountCode Used by: AST_EVENT_CEL Payload type: STR.
Definition: event_defs.h:205
const ast_string_field name
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
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)
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532