Asterisk - The Open Source Telephony Project GIT-master-57e2743
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions | Variables
cdr.c File Reference

Call Detail Record API. More...

#include "asterisk.h"
#include <signal.h>
#include <inttypes.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/callerid.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/causes.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.h"
#include "asterisk/sched.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"
#include "asterisk/config_options.h"
#include "asterisk/json.h"
#include "asterisk/parking.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_bridges.h"
#include "asterisk/stasis_message_router.h"
#include "asterisk/astobj2.h"
#include "asterisk/taskprocessor.h"
Include dependency graph for cdr.c:

Go to the source code of this file.

Data Structures

struct  be_list
 List of registered backends. More...
 
struct  bridge_leave_data
 
struct  cdr_batch
 The actual batch queue. More...
 
struct  cdr_batch_item
 Queued CDR waiting to be batched. More...
 
struct  cdr_beitem
 Registration object for CDR backends. More...
 
struct  cdr_object
 An in-memory representation of an active CDR. More...
 
struct  cdr_object_fn_table
 A virtual table used for cdr_object. More...
 
struct  cdr_object_snapshot
 A wrapper object around a snapshot. Fields that are mutable by the CDR engine are replicated here. More...
 
struct  mo_list
 List of registered modifiers. More...
 
struct  module_config
 The configuration settings for this module. More...
 
struct  party_b_userfield_update
 

Macros

#define CDR_DEBUG(fmt, ...)
 
#define cdr_set_debug_mode(mod_cfg)
 
#define DEFAULT_BATCH_SAFE_SHUTDOWN   "1"
 
#define DEFAULT_BATCH_SCHEDULER_ONLY   "0"
 
#define DEFAULT_BATCH_SIZE   "100"
 
#define DEFAULT_BATCH_TIME   "300"
 
#define DEFAULT_BATCHMODE   "0"
 
#define DEFAULT_CHANNEL_ENABLED   "1"
 
#define DEFAULT_CONGESTION   "0"
 
#define DEFAULT_ENABLED   "1"
 
#define DEFAULT_END_BEFORE_H_EXTEN   "1"
 
#define DEFAULT_IGNORE_DIAL_CHANGES   "0"
 
#define DEFAULT_IGNORE_STATE_CHANGES   "0"
 
#define DEFAULT_INITIATED_SECONDS   "0"
 
#define DEFAULT_UNANSWERED   "0"
 
#define FORMAT_STRING   "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
 
#define FORMAT_STRING   "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
 
#define MAX_BATCH_SIZE   1000
 
#define MAX_BATCH_TIME   86400
 
#define TITLE_STRING   "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
 
#define TITLE_STRING   "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
 

Enumerations

enum  process_bridge_enter_results { BRIDGE_ENTER_ONLY_PARTY , BRIDGE_ENTER_OBTAINED_PARTY_B , BRIDGE_ENTER_NO_PARTY_B , BRIDGE_ENTER_NEED_CDR }
 Return types for process_bridge_enter functions. More...
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static AO2_GLOBAL_OBJ_STATIC (module_configs)
 The container for the module configuration.
 
struct ast_cdr * ast_cdr_alloc (void)
 Allocate a CDR record.
 
int ast_cdr_backend_suspend (const char *name)
 Suspend a CDR backend temporarily.
 
int ast_cdr_backend_unsuspend (const char *name)
 Unsuspend a CDR backend.
 
int ast_cdr_clear_property (const char *channel_name, enum ast_cdr_options option)
 Clear a property on a CDR for a channel.
 
const char * ast_cdr_disp2str (int disposition)
 Disposition to a string.
 
struct ast_cdr * ast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a public CDR.
 
void ast_cdr_engine_term (void)
 
int ast_cdr_fork (const char *channel_name, struct ast_flags *options)
 Fork a CDR.
 
void ast_cdr_format_var (struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw)
 Format a CDR variable from an already posted CDR.
 
void ast_cdr_free (struct ast_cdr *cdr)
 Free a CDR record.
 
static int ast_cdr_generic_unregister (struct be_list *generic_list, const char *name)
 
struct ast_cdr_config * ast_cdr_get_config (void)
 Obtain the current CDR configuration.
 
int ast_cdr_getvar (const char *channel_name, const char *name, char *value, size_t length)
 Retrieve a CDR variable from a channel's current CDR.
 
int ast_cdr_is_enabled (void)
 Return TRUE if CDR subsystem is enabled.
 
struct stasis_message_router * ast_cdr_message_router (void)
 Return the message router for the CDR engine.
 
int ast_cdr_modifier_register (const char *name, const char *desc, ast_cdrbe be)
 Register a CDR modifier.
 
int ast_cdr_modifier_unregister (const char *name)
 Unregister a CDR modifier.
 
int ast_cdr_register (const char *name, const char *desc, ast_cdrbe be)
 Register a CDR handling engine.
 
int ast_cdr_reset (const char *channel_name, int keep_variables)
 Reset the detail record.
 
int ast_cdr_serialize_variables (const char *channel_name, struct ast_str **buf, char delim, char sep)
 Serializes all the data and variables for a current CDR record.
 
void ast_cdr_set_config (struct ast_cdr_config *config)
 Set the current CDR configuration.
 
int ast_cdr_set_property (const char *channel_name, enum ast_cdr_options option)
 Set a property on a CDR for a channel.
 
void ast_cdr_setuserfield (const char *channel_name, const char *userfield)
 Set CDR user field for channel (stored in CDR)
 
int ast_cdr_setvar (const char *channel_name, const char *name, const char *value)
 Set a variable on a CDR.
 
int ast_cdr_unregister (const char *name)
 Unregister a CDR handling engine.
 
struct ast_module * AST_MODULE_SELF_SYM (void)
 
static enum process_bridge_enter_results base_process_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 
static int base_process_bridge_leave (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 
static int base_process_dial_end (struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
 
static int base_process_parked_channel (struct cdr_object *cdr, struct ast_parked_call_payload *parking_info)
 
static int base_process_party_a (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 
static void bridge_candidate_add_to_cdr (struct cdr_object *cdr, struct cdr_object_snapshot *party_b)
 
static void bridge_candidate_process (struct cdr_object *cdr, struct cdr_object *base_cand_cdr)
 Process a single bridge_candidate.
 
static int bridge_state_process_bridge_leave (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 
static void bridge_state_process_party_b (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 
static int cdr_all_cmp_fn (void *obj, void *arg, int flags)
 
static int cdr_all_hash_fn (const void *obj, const int flags)
 
static void cdr_all_print_fn (void *v_obj, void *where, ao2_prnt_fn *prnt)
 
static void cdr_all_relink (struct cdr_object *cdr)
 
static void cdr_all_unlink (struct cdr_object *cdr)
 
static void cdr_detach (struct ast_cdr *cdr)
 
static void cdr_enable_batch_mode (struct ast_cdr_config *config)
 
static void cdr_engine_shutdown (void)
 
static const char * cdr_format_var_internal (struct ast_cdr *cdr, const char *name)
 
static int cdr_generic_register (struct be_list *generic_list, const char *name, const char *desc, ast_cdrbe be)
 
static void cdr_get_tv (struct timeval when, const char *fmt, char *buf, int bufsize)
 
static int cdr_master_cmp_fn (void *obj, void *arg, int flags)
 
static int cdr_master_hash_fn (const void *obj, const int flags)
 
static void cdr_master_print_fn (void *v_obj, void *where, ao2_prnt_fn *prnt)
 
static struct cdr_object * cdr_object_alloc (struct ast_channel_snapshot *chan, const struct timeval *event_time)
 cdr_object constructor
 
static void cdr_object_check_party_a_answer (struct cdr_object *cdr)
 Check to see if a CDR needs to be answered based on its Party A. Note that this is safe to call as much as you want - we won't answer twice.
 
static void cdr_object_check_party_a_hangup (struct cdr_object *cdr)
 Check to see if a CDR needs to move to the finalized state because its Party A hungup.
 
static struct cdr_object * cdr_object_create_and_append (struct cdr_object *cdr, const struct timeval *event_time)
 Create a new cdr_object and append it to an existing chain.
 
static struct ast_cdr * cdr_object_create_public_records (struct cdr_object *cdr)
 Create a chain of ast_cdr objects from a chain of cdr_object suitable for consumption by the registered CDR backends.
 
static void cdr_object_dispatch (struct cdr_object *cdr)
 Dispatch a CDR.
 
static int cdr_object_dispatch_all_cb (void *obj, void *arg, int flags)
 This dispatches all cdr_object. It should only be used during shutdown, so that we get billing records for everything that we can.
 
static void cdr_object_dtor (void *obj)
 cdr_object Destructor
 
static void cdr_object_finalize (struct cdr_object *cdr)
 Finalize a CDR.
 
static int cdr_object_finalize_party_b (void *obj, void *arg, void *data, int flags)
 
static int cdr_object_format_property (struct cdr_object *cdr_obj, const char *name, char *value, size_t length)
 Format one of the standard properties on a cdr_object.
 
static void cdr_object_format_var_internal (struct cdr_object *cdr, const char *name, char *value, size_t length)
 Format a variable on a cdr_object.
 
static long cdr_object_get_billsec (struct cdr_object *cdr)
 Compute the billsec for a cdr_object.
 
static struct cdr_object * cdr_object_get_by_name (const char *name)
 
static int cdr_object_get_by_name_cb (void *obj, void *arg, int flags)
 
static long cdr_object_get_duration (struct cdr_object *cdr)
 
static int cdr_object_party_b_left_bridge_cb (void *obj, void *arg, void *data, int flags)
 Callback used to notify CDRs of a Party B leaving the bridge.
 
static struct cdr_object_snapshot * cdr_object_pick_party_a (struct cdr_object_snapshot *left, struct cdr_object_snapshot *right)
 Given two CDR snapshots, figure out who should be Party A for the resulting CDR.
 
static int cdr_object_select_all_by_name_cb (void *obj, void *arg, int flags)
 
static void cdr_object_set_disposition (struct cdr_object *cdr, int hangupcause)
 Set the disposition on a cdr_object based on a hangupcause code.
 
static void cdr_object_snapshot_copy (struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src)
 Copy a snapshot and its details.
 
static void cdr_object_swap_snapshot (struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 Swap an old cdr_object_snapshot's ast_channel_snapshot for a new ast_channel_snapshot.
 
static void cdr_object_transition_state (struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
 Transition a cdr_object to a new state.
 
static void cdr_object_transition_state_init (struct cdr_object *cdr, struct cdr_object_fn_table *fn_table, int do_init)
 Transition a cdr_object to a new state with initiation flag.
 
static void cdr_object_update_cid (struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 Set Caller ID information on a CDR.
 
static int cdr_object_update_party_b (void *obj, void *arg, void *data, int flags)
 
static int cdr_object_update_party_b_userfield_cb (void *obj, void *arg, void *data, int flags)
 Callback used to update the userfield on Party B on all CDRs.
 
static void cdr_submit_batch (int shutdown)
 
static int cdr_toggle_runtime_options (void)
 Checks if CDRs are enabled and enables/disables the necessary options.
 
static int check_new_cdr_needed (struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 Determine if we need to add a new CDR based on snapshots.
 
static char * cli_complete_show (struct ast_cli_args *a)
 Complete user input for 'cdr show'.
 
static void cli_show_channel (struct ast_cli_args *a)
 
static void cli_show_channels (struct ast_cli_args *a)
 
 CONFIG_INFO_CORE ("cdr", cfg_info, module_configs, module_config_alloc,.files=ACO_FILES(&module_file_conf),.post_apply_config=module_config_post_apply,)
 
static int copy_variables (struct varshead *to_list, struct varshead *from_list)
 Copy variables from one list to another.
 
static int create_subscriptions (void)
 Create the Stasis subscriptions for CDRs.
 
static void destroy_subscriptions (void)
 Destroy the active Stasis subscriptions.
 
static enum process_bridge_enter_results dial_state_process_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 
static int dial_state_process_dial_begin (struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
 
static int dial_state_process_dial_end (struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
 
static void dial_state_process_party_b (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 
static int dial_status_end (const char *dialstatus)
 
static enum ast_cdr_disposition dial_status_to_disposition (const char *dial_status)
 
static enum process_bridge_enter_results dialed_pending_state_process_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 
static int dialed_pending_state_process_dial_begin (struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
 
static int dialed_pending_state_process_parking_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 
static int dialed_pending_state_process_party_a (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 
static void * do_batch_backend_process (void *data)
 
static void * do_cdr (void *data)
 
static int filter_bridge_messages (struct ast_bridge_snapshot *bridge)
 Filter bridge messages based on bridge technology.
 
static int filter_channel_snapshot (struct ast_channel_snapshot *snapshot)
 
static int filter_channel_snapshot_message (struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 
static void finalize_batch_mode (void)
 
static void finalized_state_init_function (struct cdr_object *cdr)
 
static int finalized_state_process_party_a (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 
static void free_variables (struct varshead *headp)
 Delete all variables from a variable list.
 
static void handle_bridge_enter_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 
static void handle_bridge_leave_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for when a channel leaves a bridge.
 
static void handle_bridge_pairings (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge)
 Handle creating bridge pairings for the cdr_object that just entered a bridge.
 
static void handle_cdr_sync_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for a synchronization message.
 
static void handle_channel_snapshot_update_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for channel snapshot update messages.
 
static char * handle_cli_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_submit (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void handle_dial_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for Stasis-Core dial messages.
 
static void handle_parked_call_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for when a channel is parked.
 
static void handle_parking_bridge_enter_message (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel, const struct timeval *event_time)
 Handle entering into a parking bridge.
 
static void handle_standard_bridge_enter_message (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel, const struct timeval *event_time)
 Handle a bridge enter message for a 'normal' bridge.
 
static int init_batch (void)
 
static int is_cdr_flag_set (unsigned int cdr_flag)
 
static int load_module (void)
 
static void * module_config_alloc (void)
 Create a new module config object.
 
static void module_config_destructor (void *obj)
 Dispose of a module config object.
 
static void module_config_post_apply (void)
 
static int parked_state_process_bridge_leave (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 
static void post_cdr (struct ast_cdr *cdr)
 
static int process_config (int reload)
 
static int reload_module (void)
 
static void reset_batch (void)
 
static void set_variable (struct varshead *headp, const char *name, const char *value)
 
static int single_state_bridge_enter_comparison (struct cdr_object *cdr, struct cdr_object *cand_cdr)
 Handle a comparison between our cdr_object and a cdr_object already in the bridge while in the Single state. The goal of this is to find a Party B for our CDR.
 
static void single_state_init_function (struct cdr_object *cdr)
 
static enum process_bridge_enter_results single_state_process_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 
static int single_state_process_dial_begin (struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
 
static int single_state_process_parking_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 
static void single_state_process_party_b (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 
static int snapshot_cep_changed (struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 Return whether or not a channel has changed its state in the dialplan, subject to endbeforehexten logic.
 
static int snapshot_is_dialed (struct ast_channel_snapshot *snapshot)
 Return whether or not a ast_channel_snapshot is for a channel that was created as the result of a dial operation.
 
static void start_batch_mode (void)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (cdr_sync_message_type)
 A message type used to synchronize with the CDR topic.
 
static int submit_scheduled_batch (const void *data)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "CDR Engine" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_CORE, .requires = "extconfig", }
 
static struct ao2_container * active_cdrs_all
 A container of all active CDRs with a Party B indexed by Party B channel name.
 
static struct ao2_container * active_cdrs_master
 A container of the active master CDRs indexed by Party A channel uniqueid.
 
static const struct ast_module_info * ast_module_info = &__mod_info
 
static struct cdr_batch * batch = NULL
 
static struct be_list be_list = AST_RWLIST_HEAD_INIT_VALUE
 
struct cdr_object_fn_table bridge_state_fn_table
 The virtual table for the Bridged state.
 
static struct stasis_forward * bridge_subscription
 Our subscription for bridges.
 
static ast_mutex_t cdr_batch_lock = AST_MUTEX_INIT_VALUE
 Lock protecting modifications to the batch queue.
 
static int cdr_debug_enabled
 
static ast_cond_t cdr_pending_cond
 
static ast_mutex_t cdr_pending_lock = AST_MUTEX_INIT_VALUE
 These are used to wake up the CDR thread when there's work to do.
 
static const char *const cdr_readonly_vars []
 
static int cdr_sched = -1
 
static ast_mutex_t cdr_sched_lock = AST_MUTEX_INIT_VALUE
 
static pthread_t cdr_thread = AST_PTHREADT_NULL
 
static struct stasis_topic * cdr_topic
 The parent topic for all topics we want to aggregate for CDRs.
 
static struct stasis_forward * channel_subscription
 Our subscription for channels.
 
static struct ast_cli_entry cli_commands []
 
static int dial_changes_ignored
 
struct cdr_object_fn_table dial_state_fn_table
 The virtual table for the Dial state.
 
struct cdr_object_fn_table dialed_pending_state_fn_table
 The virtual table for the Dialed Pending state.
 
struct cdr_object_fn_table finalized_state_fn_table
 The virtual table for the finalized state.
 
static struct aco_type general_option
 The type definition for general options.
 
static struct aco_type * general_options [] = ACO_TYPES(&general_option)
 
static int global_cdr_sequence = 0
 The global sequence counter used for CDRs.
 
static const char * ignore_categories []
 
static struct aco_type ignore_option
 
static struct mo_list mo_list = AST_RWLIST_HEAD_INIT_VALUE
 
static struct aco_file module_file_conf
 The file definition.
 
struct cdr_object_fn_table parked_state_fn_table
 The virtual table for the Parked state.
 
static struct stasis_forward * parking_subscription
 Our subscription for parking.
 
static struct ast_sched_context * sched
 Scheduler items.
 
struct cdr_object_fn_table single_state_fn_table
 The virtual table for the Single state.
 
static struct stasis_message_router * stasis_router
 Message router for stasis messages regarding channel state.
 

Detailed Description

Call Detail Record API.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Note
Includes code and algorithms from the Zapata library.
We do a lot of checking here in the CDR code to try to be sure we don't ever let a CDR slip through our fingers somehow. If someone allocates a CDR, it must be completely handled normally or a WARNING shall be logged, so that we can best keep track of any escape condition where the CDR isn't properly generated and posted.

Definition in file cdr.c.

Macro Definition Documentation

◆ CDR_DEBUG

#define CDR_DEBUG (   fmt,
  ... 
)
Value:
do { \
ast_verbose((fmt), ##__VA_ARGS__); \
} \
} while (0)
static int cdr_debug_enabled
Definition cdr.c:311

Definition at line 314 of file cdr.c.

315 { \
316 if (cdr_debug_enabled) { \
317 ast_verbose((fmt), ##__VA_ARGS__); \
318 } \
319 } while (0)

◆ cdr_set_debug_mode

#define cdr_set_debug_mode (   mod_cfg)
Value:
do { \
cdr_debug_enabled = ast_test_flag(&(mod_cfg)->general->settings, CDR_DEBUG); \
} while (0)
#define CDR_DEBUG(fmt,...)
Definition cdr.c:314
#define ast_test_flag(p, flag)
Definition utils.h:64

Definition at line 306 of file cdr.c.

307 { \
308 cdr_debug_enabled = ast_test_flag(&(mod_cfg)->general->settings, CDR_DEBUG); \
309 } while (0)

◆ DEFAULT_BATCH_SAFE_SHUTDOWN

#define DEFAULT_BATCH_SAFE_SHUTDOWN   "1"

Definition at line 304 of file cdr.c.

◆ DEFAULT_BATCH_SCHEDULER_ONLY

#define DEFAULT_BATCH_SCHEDULER_ONLY   "0"

Definition at line 303 of file cdr.c.

◆ DEFAULT_BATCH_SIZE

#define DEFAULT_BATCH_SIZE   "100"

Definition at line 299 of file cdr.c.

◆ DEFAULT_BATCH_TIME

#define DEFAULT_BATCH_TIME   "300"

Definition at line 301 of file cdr.c.

◆ DEFAULT_BATCHMODE

#define DEFAULT_BATCHMODE   "0"

Definition at line 290 of file cdr.c.

◆ DEFAULT_CHANNEL_ENABLED

#define DEFAULT_CHANNEL_ENABLED   "1"

Definition at line 295 of file cdr.c.

◆ DEFAULT_CONGESTION

#define DEFAULT_CONGESTION   "0"

Definition at line 292 of file cdr.c.

◆ DEFAULT_ENABLED

#define DEFAULT_ENABLED   "1"

Definition at line 289 of file cdr.c.

◆ DEFAULT_END_BEFORE_H_EXTEN

#define DEFAULT_END_BEFORE_H_EXTEN   "1"

Definition at line 293 of file cdr.c.

◆ DEFAULT_IGNORE_DIAL_CHANGES

#define DEFAULT_IGNORE_DIAL_CHANGES   "0"

Definition at line 297 of file cdr.c.

◆ DEFAULT_IGNORE_STATE_CHANGES

#define DEFAULT_IGNORE_STATE_CHANGES   "0"

Definition at line 296 of file cdr.c.

◆ DEFAULT_INITIATED_SECONDS

#define DEFAULT_INITIATED_SECONDS   "0"

Definition at line 294 of file cdr.c.

◆ DEFAULT_UNANSWERED

#define DEFAULT_UNANSWERED   "0"

Definition at line 291 of file cdr.c.

◆ FORMAT_STRING [1/2]

#define FORMAT_STRING   "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"

◆ FORMAT_STRING [2/2]

#define FORMAT_STRING   "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"

◆ MAX_BATCH_SIZE

#define MAX_BATCH_SIZE   1000

Definition at line 300 of file cdr.c.

◆ MAX_BATCH_TIME

#define MAX_BATCH_TIME   86400

Definition at line 302 of file cdr.c.

◆ TITLE_STRING [1/2]

#define TITLE_STRING   "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"

◆ TITLE_STRING [2/2]

#define TITLE_STRING   "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"

Enumeration Type Documentation

◆ process_bridge_enter_results

Return types for process_bridge_enter functions.

Enumerator
BRIDGE_ENTER_ONLY_PARTY 

The CDR was the only party in the bridge.

BRIDGE_ENTER_OBTAINED_PARTY_B 

The CDR was able to obtain a Party B from some other party already in the bridge

BRIDGE_ENTER_NO_PARTY_B 

The CDR was not able to obtain a Party B

BRIDGE_ENTER_NEED_CDR 

This CDR can't handle a bridge enter message and a new CDR needs to be created

Definition at line 495 of file cdr.c.

495 {
496 /*!
497 * The CDR was the only party in the bridge.
498 */
500 /*!
501 * The CDR was able to obtain a Party B from some other party already in the bridge
502 */
504 /*!
505 * The CDR was not able to obtain a Party B
506 */
508 /*!
509 * This CDR can't handle a bridge enter message and a new CDR needs to be created
510 */
512};
@ BRIDGE_ENTER_ONLY_PARTY
Definition cdr.c:499
@ BRIDGE_ENTER_NO_PARTY_B
Definition cdr.c:507
@ BRIDGE_ENTER_NEED_CDR
Definition cdr.c:511
@ BRIDGE_ENTER_OBTAINED_PARTY_B
Definition cdr.c:503

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 4832 of file cdr.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 4832 of file cdr.c.

◆ AO2_GLOBAL_OBJ_STATIC()

static AO2_GLOBAL_OBJ_STATIC ( module_configs  )
static

The container for the module configuration.

◆ ast_cdr_alloc()

struct ast_cdr * ast_cdr_alloc ( void  )

Allocate a CDR record.

Returns
a malloc'd ast_cdr structure
Return values
NULLon error (malloc failure)

Definition at line 3573 of file cdr.c.

3574{
3575 struct ast_cdr *x;
3576
3577 x = ast_calloc(1, sizeof(*x));
3578 return x;
3579}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
Responsible for call detail data.
Definition cdr.h:281

References ast_calloc.

Referenced by ast_cdr_dup().

◆ ast_cdr_backend_suspend()

int ast_cdr_backend_suspend ( const char *  name)

Suspend a CDR backend temporarily.

Return values
0The backend is suspended
-1The backend could not be suspended

Definition at line 3004 of file cdr.c.

3005{
3006 int success = -1;
3007 struct cdr_beitem *i = NULL;
3008
3011 if (!strcasecmp(name, i->name)) {
3012 ast_debug(3, "Suspending CDR backend %s\n", i->name);
3013 i->suspended = 1;
3014 success = 0;
3015 }
3016 }
3018
3019 return success;
3020}
static const char name[]
Definition format_mp3.c:68
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_RWLIST_TRAVERSE
#define NULL
Definition resample.c:96
List of registered backends.
Definition cdr.c:434
Registration object for CDR backends.
Definition cdr.c:425
struct cdr_beitem::@347 list
char name[20]
Definition cdr.c:426
int suspended
Definition cdr.c:430

References ast_debug, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, cdr_beitem::list, cdr_beitem::name, name, NULL, and cdr_beitem::suspended.

Referenced by load_config(), load_config(), and odbc_load_module().

◆ ast_cdr_backend_unsuspend()

int ast_cdr_backend_unsuspend ( const char *  name)

Unsuspend a CDR backend.

Return values
0The backend was unsuspended
-1The back could not be unsuspended

Definition at line 3022 of file cdr.c.

3023{
3024 int success = -1;
3025 struct cdr_beitem *i = NULL;
3026
3029 if (!strcasecmp(name, i->name)) {
3030 ast_debug(3, "Unsuspending CDR backend %s\n", i->name);
3031 i->suspended = 0;
3032 success = 0;
3033 }
3034 }
3036
3037 return success;
3038}

References ast_debug, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, cdr_beitem::list, cdr_beitem::name, name, NULL, and cdr_beitem::suspended.

Referenced by load_config(), load_config(), and odbc_load_module().

◆ ast_cdr_clear_property()

int ast_cdr_clear_property ( const char *  channel_name,
enum ast_cdr_options  option 
)

Clear a property on a CDR for a channel.

Since
12

Clears a flag previously set by ast_cdr_set_property

Parameters
channel_nameThe CDR's channel
optionOption to clear from the CDR
Return values
0on success
1on error

Definition at line 3728 of file cdr.c.

3729{
3730 struct cdr_object *cdr;
3731 struct cdr_object *it_cdr;
3732
3733 cdr = cdr_object_get_by_name(channel_name);
3734 if (!cdr) {
3735 return -1;
3736 }
3737
3738 ao2_lock(cdr);
3739 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3740 if (it_cdr->fn_table == &finalized_state_fn_table) {
3741 continue;
3742 }
3743 ast_clear_flag(&it_cdr->flags, option);
3744 }
3745 ao2_unlock(cdr);
3746
3747 ao2_cleanup(cdr);
3748 return 0;
3749}
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
struct cdr_object_fn_table finalized_state_fn_table
The virtual table for the finalized state.
Definition cdr.c:798
static struct cdr_object * cdr_object_get_by_name(const char *name)
Definition cdr.c:3463
An in-memory representation of an active CDR.
Definition cdr.c:816
struct timeval start
Definition cdr.c:822
#define ast_clear_flag(p, flag)
Definition utils.h:78

References ao2_cleanup, ao2_lock, ao2_unlock, ast_clear_flag, cdr_object_get_by_name(), finalized_state_fn_table, cdr_object::next, and cdr_object::start.

Referenced by AST_TEST_DEFINE(), and cdr_prop_write_callback().

◆ ast_cdr_disp2str()

const char * ast_cdr_disp2str ( int  disposition)

Disposition to a string.

Parameters
dispositioninput binary form Converts the binary form of a disposition to string form.
Returns
a pointer to the string form

Definition at line 3581 of file cdr.c.

3582{
3583 switch (disposition) {
3584 case AST_CDR_NULL:
3585 return "NO ANSWER"; /* by default, for backward compatibility */
3586 case AST_CDR_NOANSWER:
3587 return "NO ANSWER";
3588 case AST_CDR_FAILED:
3589 return "FAILED";
3590 case AST_CDR_BUSY:
3591 return "BUSY";
3592 case AST_CDR_ANSWERED:
3593 return "ANSWERED";
3594 case AST_CDR_CONGESTION:
3595 return "CONGESTION";
3596 case AST_CDR_CANCEL:
3597 return "CANCEL";
3598 }
3599 return "UNKNOWN";
3600}
@ AST_CDR_CONGESTION
Definition cdr.h:263
@ AST_CDR_NULL
Definition cdr.h:259
@ AST_CDR_NOANSWER
Definition cdr.h:258
@ AST_CDR_ANSWERED
Definition cdr.h:262
@ AST_CDR_CANCEL
Definition cdr.h:264
@ AST_CDR_BUSY
Definition cdr.h:261
@ AST_CDR_FAILED
Definition cdr.h:260

References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_CANCEL, AST_CDR_CONGESTION, AST_CDR_FAILED, AST_CDR_NOANSWER, AST_CDR_NULL, and ast_cdr::disposition.

Referenced by ast_cdr_format_var(), beanstalk_put(), build_csv_record(), build_radius_record(), cdr_object_finalize(), cdr_read_callback(), execute_cb(), format_disposition(), manager_log(), and tds_log().

◆ ast_cdr_dup()

struct ast_cdr * ast_cdr_dup ( struct ast_cdr *  cdr)

Duplicate a public CDR.

Parameters
cdrthe record to duplicate
Returns
a malloc'd ast_cdr structure,
Return values
NULLon error (malloc failure)

Definition at line 3136 of file cdr.c.

3137{
3138 struct ast_cdr *newcdr;
3139
3140 if (!cdr) {
3141 return NULL;
3142 }
3144 if (!newcdr) {
3145 return NULL;
3146 }
3147
3148 *newcdr = *cdr;
3150 copy_variables(&newcdr->varshead, &cdr->varshead);
3151 newcdr->next = NULL;
3152
3153 return newcdr;
3154}
struct ast_cdr * ast_cdr_alloc(void)
Allocate a CDR record.
Definition cdr.c:3573
static int copy_variables(struct varshead *to_list, struct varshead *from_list)
Copy variables from one list to another.
Definition cdr.c:851
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
struct varshead varshead
Definition cdr.h:332
struct timeval start
Definition cdr.h:299

References ast_cdr_alloc(), AST_LIST_HEAD_INIT_NOLOCK, copy_variables(), NULL, ast_cdr::start, and ast_cdr::varshead.

Referenced by dummy_chan_alloc_cdr(), and manager_log().

◆ ast_cdr_engine_term()

void ast_cdr_engine_term ( void  )

Submit any remaining CDRs and prepare for shutdown

Definition at line 4758 of file cdr.c.

4759{
4760 RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
4761
4762 /* Since this is called explicitly during process shutdown, we might not have ever
4763 * been initialized. If so, the config object will be NULL.
4764 */
4765 if (!mod_cfg) {
4766 return;
4767 }
4768
4769 if (cdr_sync_message_type()) {
4770 void *payload;
4771 struct stasis_message *message;
4772
4773 if (!stasis_router) {
4774 return;
4775 }
4776
4777 /* Make sure we have the needed items */
4778 payload = ao2_alloc(sizeof(*payload), NULL);
4779 if (!payload) {
4780 return;
4781 }
4782
4783 ast_debug(1, "CDR Engine termination request received; waiting on messages...\n");
4784
4785 message = stasis_message_create(cdr_sync_message_type(), payload);
4786 if (message) {
4788 }
4790 ao2_cleanup(payload);
4791 }
4792
4793 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4794 cdr_submit_batch(ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN));
4795 }
4796}
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition astobj2.h:918
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
static struct stasis_message_router * stasis_router
Message router for stasis messages regarding channel state.
Definition cdr.c:475
static void cdr_submit_batch(int shutdown)
Definition cdr.c:3919
@ CDR_BATCHMODE
Definition cdr.h:221
@ BATCH_MODE_SAFE_SHUTDOWN
Definition cdr.h:236
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_message_router_publish_sync(struct stasis_message_router *router, struct stasis_message *message)
Publish a message to a message router's subscription synchronously.
The configuration settings for this module.
Definition cdr.c:326
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981

References ao2_alloc, ao2_cleanup, ao2_global_obj_ref, ast_debug, ast_test_flag, BATCH_MODE_SAFE_SHUTDOWN, CDR_BATCHMODE, cdr_submit_batch(), NULL, RAII_VAR, stasis_message_create(), stasis_message_router_publish_sync(), and stasis_router.

Referenced by can_safely_quit(), and finalize_batch_mode().

◆ ast_cdr_fork()

int ast_cdr_fork ( const char *  channel_name,
struct ast_flags *  options 
)

Fork a CDR.

Since
12
Parameters
channel_nameThe name of the channel whose CDR should be forked
optionsOptions to control how the fork occurs.
Return values
0on success
-1on failure

Definition at line 3790 of file cdr.c.

3791{
3792 RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
3793 struct cdr_object *new_cdr;
3794 struct cdr_object *it_cdr;
3795 struct cdr_object *cdr_obj;
3796
3797 if (!cdr) {
3798 return -1;
3799 }
3800
3801 {
3802 SCOPED_AO2LOCK(lock, cdr);
3803 struct timeval now = ast_tvnow();
3804
3805 cdr_obj = cdr->last;
3806 if (cdr_obj->fn_table == &finalized_state_fn_table) {
3807 /* If the last CDR in the chain is finalized, don't allow a fork -
3808 * things are already dying at this point
3809 */
3810 return -1;
3811 }
3812
3813 /* Copy over the basic CDR information. The Party A information is
3814 * copied over automatically as part of the append
3815 */
3816 ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
3817 new_cdr = cdr_object_create_and_append(cdr, &now);
3818 if (!new_cdr) {
3819 return -1;
3820 }
3821 new_cdr->fn_table = cdr_obj->fn_table;
3822 ast_string_field_set(new_cdr, bridge, cdr->bridge);
3823 ast_string_field_set(new_cdr, appl, cdr->appl);
3824 ast_string_field_set(new_cdr, data, cdr->data);
3825 ast_string_field_set(new_cdr, context, cdr->context);
3826 ast_string_field_set(new_cdr, exten, cdr->exten);
3827 new_cdr->flags = cdr->flags;
3828 /* Explicitly clear the AST_CDR_LOCK_APP flag - we want
3829 * the application to be changed on the new CDR if the
3830 * dialplan demands it
3831 */
3833
3834 /* If there's a Party B, copy it over as well */
3835 if (cdr_obj->party_b.snapshot) {
3836 new_cdr->party_b.snapshot = cdr_obj->party_b.snapshot;
3837 ao2_ref(new_cdr->party_b.snapshot, +1);
3838 cdr_all_relink(new_cdr);
3839 strcpy(new_cdr->party_b.userfield, cdr_obj->party_b.userfield);
3840 new_cdr->party_b.flags = cdr_obj->party_b.flags;
3842 copy_variables(&new_cdr->party_b.variables, &cdr_obj->party_b.variables);
3843 }
3844 }
3845 new_cdr->start = cdr_obj->start;
3846 new_cdr->answer = cdr_obj->answer;
3847 new_cdr->lastevent = ast_tvnow();
3848
3849 /* Modify the times based on the flags passed in */
3851 && new_cdr->party_a.snapshot->state == AST_STATE_UP) {
3852 new_cdr->answer = ast_tvnow();
3853 }
3855 new_cdr->answer = ast_tvnow();
3856 new_cdr->start = ast_tvnow();
3857 }
3858
3859 /* Create and append, by default, copies over the variables */
3861 free_variables(&new_cdr->party_a.variables);
3862 }
3863
3864 /* Finalize any current CDRs */
3866 for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->next) {
3867 if (it_cdr->fn_table == &finalized_state_fn_table) {
3868 continue;
3869 }
3870 /* Force finalization on the CDR. This will bypass any checks for
3871 * end before 'h' extension.
3872 */
3873 cdr_object_finalize(it_cdr);
3875 }
3876 }
3877 }
3878
3879 return 0;
3880}
ast_mutex_t lock
Definition app_sla.c:337
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
static struct cdr_object * cdr_object_create_and_append(struct cdr_object *cdr, const struct timeval *event_time)
Create a new cdr_object and append it to an existing chain.
Definition cdr.c:1179
static void cdr_object_finalize(struct cdr_object *cdr)
Finalize a CDR.
Definition cdr.c:1544
static void cdr_all_relink(struct cdr_object *cdr)
Definition cdr.c:1053
static void free_variables(struct varshead *headp)
Delete all variables from a variable list.
Definition cdr.c:882
static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
Transition a cdr_object to a new state.
Definition cdr.c:927
@ AST_CDR_LOCK_APP
Definition cdr.h:251
@ AST_CDR_FLAG_FINALIZE
Definition cdr.h:248
@ AST_CDR_FLAG_KEEP_VARS
Definition cdr.h:244
@ AST_CDR_FLAG_RESET
Definition cdr.h:250
@ AST_CDR_FLAG_SET_ANSWER
Definition cdr.h:249
@ AST_STATE_UP
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition lock.h:611
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
enum ast_channel_state state
unsigned int flags
Definition utils.h:221
char userfield[AST_MAX_USER_FIELD]
Definition cdr.c:810
struct varshead variables
Definition cdr.c:812
struct ast_channel_snapshot * snapshot
Definition cdr.c:809
unsigned int flags
Definition cdr.c:811
struct cdr_object_fn_table * fn_table
Definition cdr.c:819
struct cdr_object * next
Definition cdr.c:840
struct timeval answer
Definition cdr.c:823
struct cdr_object_snapshot party_a
Definition cdr.c:817
struct timeval lastevent
Definition cdr.c:825
struct cdr_object * last
Definition cdr.c:841
struct ast_flags flags
Definition cdr.c:827
struct cdr_object_snapshot party_b
Definition cdr.c:818
static struct test_options options
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

References cdr_object::answer, ao2_cleanup, ao2_ref, cdr_object::appl, AST_CDR_FLAG_FINALIZE, AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_RESET, AST_CDR_FLAG_SET_ANSWER, AST_CDR_LOCK_APP, ast_clear_flag, ast_debug, AST_STATE_UP, ast_string_field_set, ast_test_flag, ast_tvnow(), cdr_object::bridge, cdr_all_relink(), cdr_object_create_and_append(), cdr_object_finalize(), cdr_object_get_by_name(), cdr_object_transition_state(), copy_variables(), cdr_object::data, cdr_object::exten, finalized_state_fn_table, ast_flags::flags, cdr_object_snapshot::flags, cdr_object::flags, cdr_object::fn_table, free_variables(), cdr_object::last, cdr_object::lastevent, lock, cdr_object::next, options, cdr_object::party_a, cdr_object::party_b, RAII_VAR, SCOPED_AO2LOCK, cdr_object_snapshot::snapshot, cdr_object::start, ast_channel_snapshot::state, cdr_object_snapshot::userfield, and cdr_object_snapshot::variables.

Referenced by AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), and forkcdr_callback().

◆ ast_cdr_format_var()

void ast_cdr_format_var ( struct ast_cdr *  cdr,
const char *  name,
char **  ret,
char *  workspace,
int  workspacelen,
int  raw 
)

Format a CDR variable from an already posted CDR.

Since
12
Parameters
cdrThe dispatched CDR to process
nameThe name of the variable
retPointer to the formatted buffer
workspaceA pointer to the buffer to use to format the variable
workspacelenThe size of workspace
rawIf non-zero and a date/time is extracted, provide epoch seconds. Otherwise format as a date/time stamp

Definition at line 3188 of file cdr.c.

3189{
3190 const char *fmt = "%Y-%m-%d %T";
3191 const char *varbuf;
3192
3193 if (!cdr) {
3194 return;
3195 }
3196
3197 *ret = NULL;
3198
3199 if (!strcasecmp(name, "clid")) {
3200 ast_copy_string(workspace, cdr->clid, workspacelen);
3201 } else if (!strcasecmp(name, "src")) {
3202 ast_copy_string(workspace, cdr->src, workspacelen);
3203 } else if (!strcasecmp(name, "dst")) {
3204 ast_copy_string(workspace, cdr->dst, workspacelen);
3205 } else if (!strcasecmp(name, "dcontext")) {
3206 ast_copy_string(workspace, cdr->dcontext, workspacelen);
3207 } else if (!strcasecmp(name, "channel")) {
3208 ast_copy_string(workspace, cdr->channel, workspacelen);
3209 } else if (!strcasecmp(name, "dstchannel")) {
3210 ast_copy_string(workspace, cdr->dstchannel, workspacelen);
3211 } else if (!strcasecmp(name, "lastapp")) {
3212 ast_copy_string(workspace, cdr->lastapp, workspacelen);
3213 } else if (!strcasecmp(name, "lastdata")) {
3214 ast_copy_string(workspace, cdr->lastdata, workspacelen);
3215 } else if (!strcasecmp(name, "start")) {
3216 cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
3217 } else if (!strcasecmp(name, "answer")) {
3218 cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
3219 } else if (!strcasecmp(name, "end")) {
3220 cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
3221 } else if (!strcasecmp(name, "duration")) {
3222 snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
3223 } else if (!strcasecmp(name, "billsec")) {
3224 snprintf(workspace, workspacelen, "%ld", (cdr->billsec || !ast_tvzero(cdr->end) || ast_tvzero(cdr->answer)) ? cdr->billsec : (long)ast_tvdiff_ms(ast_tvnow(), cdr->answer) / 1000);
3225 } else if (!strcasecmp(name, "disposition")) {
3226 if (raw) {
3227 snprintf(workspace, workspacelen, "%ld", cdr->disposition);
3228 } else {
3229 ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
3230 }
3231 } else if (!strcasecmp(name, "amaflags")) {
3232 if (raw) {
3233 snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
3234 } else {
3235 ast_copy_string(workspace, ast_channel_amaflags2string(cdr->amaflags), workspacelen);
3236 }
3237 } else if (!strcasecmp(name, "accountcode")) {
3238 ast_copy_string(workspace, cdr->accountcode, workspacelen);
3239 } else if (!strcasecmp(name, "peeraccount")) {
3240 ast_copy_string(workspace, cdr->peeraccount, workspacelen);
3241 } else if (!strcasecmp(name, "uniqueid")) {
3242 ast_copy_string(workspace, cdr->uniqueid, workspacelen);
3243 } else if (!strcasecmp(name, "linkedid")) {
3244 ast_copy_string(workspace, cdr->linkedid, workspacelen);
3245 } else if (!strcasecmp(name, "tenantid")) {
3246 ast_copy_string(workspace, cdr->tenantid, workspacelen);
3247 } else if (!strcasecmp(name, "peertenantid")) {
3248 ast_copy_string(workspace, cdr->peertenantid, workspacelen);
3249 } else if (!strcasecmp(name, "userfield")) {
3250 ast_copy_string(workspace, cdr->userfield, workspacelen);
3251 } else if (!strcasecmp(name, "sequence")) {
3252 snprintf(workspace, workspacelen, "%d", cdr->sequence);
3253 } else if ((varbuf = cdr_format_var_internal(cdr, name))) {
3254 ast_copy_string(workspace, varbuf, workspacelen);
3255 } else {
3256 workspace[0] = '\0';
3257 }
3258
3259 if (!ast_strlen_zero(workspace)) {
3260 *ret = workspace;
3261 }
3262}
static void cdr_get_tv(struct timeval when, const char *fmt, char *buf, int bufsize)
Definition cdr.c:3173
static const char * cdr_format_var_internal(struct ast_cdr *cdr, const char *name)
Definition cdr.c:3156
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition cdr.c:3581
static int answer(void *data)
Definition chan_pjsip.c:793
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition channel.c:4395
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
char dstchannel[AST_MAX_EXTENSION]
Definition cdr.h:293
long int disposition
Definition cdr.h:309
char lastdata[AST_MAX_EXTENSION]
Definition cdr.h:297
char linkedid[AST_MAX_UNIQUEID]
Definition cdr.h:321
char userfield[AST_MAX_USER_FIELD]
Definition cdr.h:327
char peertenantid[AST_MAX_TENANT_ID]
Definition cdr.h:325
long int billsec
Definition cdr.h:307
struct timeval answer
Definition cdr.h:301
char channel[AST_MAX_EXTENSION]
Definition cdr.h:291
char peeraccount[AST_MAX_ACCOUNT_CODE]
Definition cdr.h:315
long int duration
Definition cdr.h:305
long int amaflags
Definition cdr.h:311
char src[AST_MAX_EXTENSION]
Definition cdr.h:285
char dst[AST_MAX_EXTENSION]
Definition cdr.h:287
char clid[AST_MAX_EXTENSION]
Definition cdr.h:283
char uniqueid[AST_MAX_UNIQUEID]
Definition cdr.h:319
char tenantid[AST_MAX_TENANT_ID]
Definition cdr.h:323
int sequence
Definition cdr.h:329
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition cdr.h:313
char lastapp[AST_MAX_EXTENSION]
Definition cdr.h:295
char dcontext[AST_MAX_EXTENSION]
Definition cdr.h:289
struct timeval end
Definition cdr.h:303
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition time.h:117
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_disp2str(), ast_channel_amaflags2string(), ast_copy_string(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_cdr::billsec, cdr_format_var_internal(), cdr_get_tv(), ast_cdr::channel, ast_cdr::clid, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::linkedid, name, NULL, ast_cdr::peeraccount, ast_cdr::peertenantid, ast_cdr::sequence, ast_cdr::src, ast_cdr::start, ast_cdr::tenantid, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by cdr_read_callback(), cdr_retrieve_time(), odbc_log(), and pgsql_log().

◆ ast_cdr_free()

void ast_cdr_free ( struct ast_cdr *  cdr)

Free a CDR record.

Parameters
cdrast_cdr structure to free

Definition at line 3562 of file cdr.c.

3563{
3564 while (cdr) {
3565 struct ast_cdr *next = cdr->next;
3566
3567 free_variables(&cdr->varshead);
3568 ast_free(cdr);
3569 cdr = next;
3570 }
3571}
#define ast_free(a)
Definition astmm.h:180
struct ast_cdr * next
Definition cdr.h:334

References ast_free, free_variables(), ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_channel_destructor(), ast_dummy_channel_destructor(), cdr_detach(), clear_mock_cdr_backend(), and do_batch_backend_process().

◆ ast_cdr_generic_unregister()

static int ast_cdr_generic_unregister ( struct be_list *  generic_list,
const char *  name 
)
static

Definition at line 3091 of file cdr.c.

3092{
3093 struct cdr_beitem *match = NULL;
3094 int active_count;
3095
3096 AST_RWLIST_WRLOCK(generic_list);
3097 AST_RWLIST_TRAVERSE(generic_list, match, list) {
3098 if (!strcasecmp(name, match->name)) {
3099 break;
3100 }
3101 }
3102
3103 if (!match) {
3104 AST_RWLIST_UNLOCK(generic_list);
3105 return 0;
3106 }
3107
3109
3110 if (!match->suspended && active_count != 0) {
3111 AST_RWLIST_UNLOCK(generic_list);
3112 ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
3113 name, active_count);
3114 return -1;
3115 }
3116
3117 AST_RWLIST_REMOVE(generic_list, match, list);
3118 AST_RWLIST_UNLOCK(generic_list);
3119
3120 ast_verb(5, "Unregistered '%s' CDR backend\n", name);
3121 ast_free(match);
3122
3123 return 0;
3124}
#define ast_log
Definition astobj2.c:42
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static struct ao2_container * active_cdrs_master
A container of the active master CDRs indexed by Party A channel uniqueid.
Definition cdr.c:469
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition chan_iax2.c:2401
#define AST_LOG_WARNING
#define ast_verb(level,...)
#define AST_RWLIST_REMOVE

References active_cdrs_master, ao2_container_count(), ast_free, ast_log, AST_LOG_WARNING, AST_RWLIST_REMOVE, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, cdr_beitem::list, match(), name, and NULL.

Referenced by ast_cdr_modifier_unregister(), and ast_cdr_unregister().

◆ ast_cdr_get_config()

struct ast_cdr_config * ast_cdr_get_config ( void  )

Obtain the current CDR configuration.

Since
12

The configuration is a ref counted object. The caller of this function must decrement the ref count when finished with the configuration.

Return values
NULLon error
Returns
The current CDR configuration

Definition at line 2964 of file cdr.c.

2965{
2966 struct ast_cdr_config *general;
2967 struct module_config *mod_cfg;
2968
2969 mod_cfg = ao2_global_obj_ref(module_configs);
2970 if (!mod_cfg) {
2971 return NULL;
2972 }
2973 general = ao2_bump(mod_cfg->general);
2974 ao2_cleanup(mod_cfg);
2975 return general;
2976}
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
The global options available for CDRs.
Definition cdr.h:269
struct ast_cdr_config * general
Definition cdr.c:327

References ao2_bump, ao2_cleanup, ao2_global_obj_ref, module_config::general, and NULL.

Referenced by test_cdr_init_cb().

◆ ast_cdr_getvar()

int ast_cdr_getvar ( const char *  channel_name,
const char *  name,
char *  value,
size_t  length 
)

Retrieve a CDR variable from a channel's current CDR.

Since
12
Parameters
channel_nameThe name of the party A channel that the CDR is associated with
nameThe name of the variable to retrieve
valueBuffer to hold the value
lengthThe size of the buffer
Return values
0on success
non-zeroon failure

Definition at line 3475 of file cdr.c.

3476{
3477 struct cdr_object *cdr;
3478 struct cdr_object *cdr_obj;
3479
3480 if (ast_strlen_zero(name)) {
3481 return 1;
3482 }
3483
3484 cdr = cdr_object_get_by_name(channel_name);
3485 if (!cdr) {
3486 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3487 return 1;
3488 }
3489
3490 ao2_lock(cdr);
3491
3492 cdr_obj = cdr->last;
3494 /* Property failed; attempt variable */
3496 }
3497
3498 ao2_unlock(cdr);
3499
3500 ao2_cleanup(cdr);
3501 return 0;
3502}
static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *name, char *value, size_t length)
Format one of the standard properties on a cdr_object.
Definition cdr.c:3386
static void cdr_object_format_var_internal(struct cdr_object *cdr, const char *name, char *value, size_t length)
Format a variable on a cdr_object.
Definition cdr.c:3369
#define AST_LOG_ERROR
int value
Definition syslog.c:37

References ao2_cleanup, ao2_lock, ao2_unlock, ast_log, AST_LOG_ERROR, ast_strlen_zero(), cdr_object_format_property(), cdr_object_format_var_internal(), cdr_object_get_by_name(), cdr_object::last, name, cdr_object::start, and value.

Referenced by AST_TEST_DEFINE(), AST_TEST_DEFINE(), cdr_read_callback(), and cdr_retrieve_time().

◆ ast_cdr_is_enabled()

int ast_cdr_is_enabled ( void  )

Return TRUE if CDR subsystem is enabled.

Definition at line 2999 of file cdr.c.

3000{
3002}
static int is_cdr_flag_set(unsigned int cdr_flag)
Definition cdr.c:1229
@ CDR_ENABLED
Definition cdr.h:220

References CDR_ENABLED, and is_cdr_flag_set().

Referenced by action_coresettings(), and handle_show_settings().

◆ ast_cdr_message_router()

struct stasis_message_router * ast_cdr_message_router ( void  )

Return the message router for the CDR engine.

This returns the stasis_message_router that the CDR engine uses for dispatching Stasis Message Bus API messages. The reference on the message router is bumped and must be released by the caller of this function.

Return values
NULLif the CDR engine is disabled or unavailable
Returns
the stasis_message_router otherwise

Definition at line 4448 of file cdr.c.

4449{
4450 if (!stasis_router) {
4451 return NULL;
4452 }
4453
4455 return stasis_router;
4456}

References ao2_bump, NULL, and stasis_router.

Referenced by cdr_prop_write(), cdr_read(), cdr_write(), forkcdr_exec(), load_module(), load_module(), load_module(), publish_app_cdr_message(), unload_module(), unload_module(), and unload_module().

◆ ast_cdr_modifier_register()

int ast_cdr_modifier_register ( const char *  name,
const char *  desc,
ast_cdrbe  be 
)

Register a CDR modifier.

Parameters
namename associated with the particular CDR modifier
descdescription of the CDR modifier
befunction pointer to a CDR modifier

Used to register a Call Detail Record modifier.

This gives modules a chance to modify CDR fields before they are dispatched to registered backends (odbc, syslog, etc).

Note
The modified CDR will be passed to all registered backends for logging. For instance, if cdr_manager changes the CDR data, cdr_adaptive_odbc will also get the modified CDR.
Return values
0on success.
-1on error

Definition at line 3086 of file cdr.c.

3087{
3088 return cdr_generic_register((struct be_list *)&mo_list, name, desc, be);
3089}
static int cdr_generic_register(struct be_list *generic_list, const char *name, const char *desc, ast_cdrbe be)
Definition cdr.c:3040
static const char desc[]
Definition cdr_radius.c:84
char * be
Definition eagi_proxy.c:73
List of registered modifiers.
Definition cdr.c:437

References be, cdr_generic_register(), desc, and name.

◆ ast_cdr_modifier_unregister()

int ast_cdr_modifier_unregister ( const char *  name)

Unregister a CDR modifier.

Parameters
namename of CDR modifier to unregister Unregisters a CDR modifier by its name
Return values
0The modifier unregistered successfully
-1The modifier could not be unregistered at this time

Definition at line 3131 of file cdr.c.

3132{
3133 return ast_cdr_generic_unregister((struct be_list *)&mo_list, name);
3134}
static int ast_cdr_generic_unregister(struct be_list *generic_list, const char *name)
Definition cdr.c:3091

References ast_cdr_generic_unregister(), and name.

◆ ast_cdr_register()

int ast_cdr_register ( const char *  name,
const char *  desc,
ast_cdrbe  be 
)

Register a CDR handling engine.

Parameters
namename associated with the particular CDR handler
descdescription of the CDR handler
befunction pointer to a CDR handler Used to register a Call Detail Record handler.
Return values
0on success.
-1on error

Definition at line 3081 of file cdr.c.

3082{
3084}

References be, cdr_generic_register(), desc, and name.

Referenced by load_module(), load_module(), load_module(), load_module(), load_module(), load_module(), load_module(), load_module(), odbc_load_module(), register_backend(), and unload_module().

◆ ast_cdr_reset()

int ast_cdr_reset ( const char *  channel_name,
int  keep_variables 
)

Reset the detail record.

Parameters
channel_nameThe channel that the CDR is associated with
keep_variablesKeep the variables during the reset. If zero, variables are discarded during the reset.
Return values
0on success
-1on failure

Definition at line 3751 of file cdr.c.

3752{
3753 struct cdr_object *cdr;
3754 struct ast_var_t *vardata;
3755 struct cdr_object *it_cdr;
3756
3757 cdr = cdr_object_get_by_name(channel_name);
3758 if (!cdr) {
3759 return -1;
3760 }
3761
3762 ao2_lock(cdr);
3763 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3764 /* clear variables */
3765 if (!keep_variables) {
3766 while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_a.variables, entries))) {
3768 }
3769 if (cdr->party_b.snapshot) {
3770 while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_b.variables, entries))) {
3772 }
3773 }
3774 }
3775
3776 /* Reset to initial state */
3777 memset(&it_cdr->start, 0, sizeof(it_cdr->start));
3778 memset(&it_cdr->end, 0, sizeof(it_cdr->end));
3779 memset(&it_cdr->answer, 0, sizeof(it_cdr->answer));
3780 it_cdr->start = ast_tvnow();
3781 it_cdr->lastevent = it_cdr->start;
3783 }
3784 ao2_unlock(cdr);
3785
3786 ao2_cleanup(cdr);
3787 return 0;
3788}
static void cdr_object_check_party_a_answer(struct cdr_object *cdr)
Check to see if a CDR needs to be answered based on its Party A. Note that this is safe to call as mu...
Definition cdr.c:1598
void ast_var_delete(struct ast_var_t *var)
Definition extconf.c:2467
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.

References ao2_cleanup, ao2_lock, ao2_unlock, AST_LIST_REMOVE_HEAD, ast_tvnow(), ast_var_delete(), cdr_object_check_party_a_answer(), cdr_object_get_by_name(), cdr_object::next, cdr_object::party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by appcdr_callback(), and dial_exec_full().

◆ ast_cdr_serialize_variables()

int ast_cdr_serialize_variables ( const char *  channel_name,
struct ast_str **  buf,
char  delim,
char  sep 
)

Serializes all the data and variables for a current CDR record.

Parameters
channel_nameThe channel to get the CDR for
bufA buffer to use for formatting the data
delimA delimeter to use to separate variable keys/values
sepA separator to use between nestings
Returns
the total number of serialized variables

Definition at line 3504 of file cdr.c.

3505{
3506 struct cdr_object *cdr;
3507 struct cdr_object *it_cdr;
3508 struct ast_var_t *variable;
3509 const char *var;
3510 char workspace[256];
3511 int total = 0, x = 0, i;
3512
3513 cdr = cdr_object_get_by_name(channel_name);
3514 if (!cdr) {
3516 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3517 }
3518 return 0;
3519 }
3520
3522
3523 ao2_lock(cdr);
3524 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3525 if (++x > 1) {
3526 ast_str_append(buf, 0, "\n");
3527 }
3528
3529 AST_LIST_TRAVERSE(&it_cdr->party_a.variables, variable, entries) {
3530 if (!(var = ast_var_name(variable))) {
3531 continue;
3532 }
3533
3534 if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variable), ""), sep) < 0) {
3535 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3536 break;
3537 }
3538
3539 total++;
3540 }
3541
3542 for (i = 0; cdr_readonly_vars[i]; i++) {
3543 if (cdr_object_format_property(it_cdr, cdr_readonly_vars[i], workspace, sizeof(workspace))) {
3544 /* Unhandled read-only CDR variable. */
3545 ast_assert(0);
3546 continue;
3547 }
3548
3549 if (!ast_strlen_zero(workspace)
3550 && ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, workspace, sep) < 0) {
3551 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3552 break;
3553 }
3554 total++;
3555 }
3556 }
3557 ao2_unlock(cdr);
3558 ao2_cleanup(cdr);
3559 return total;
3560}
#define var
Definition ast_expr2f.c:605
static const char *const cdr_readonly_vars[]
Definition cdr.c:3296
const char * ast_var_name(const struct ast_var_t *var)
Definition chanvars.c:60
const char * ast_var_value(const struct ast_var_t *var)
Definition chanvars.c:80
char buf[BUFSIZE]
Definition eagi_proxy.c:66
#define LOG_ERROR
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
static int total
Definition res_adsi.c:970
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
#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
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition strings.h:693
struct ast_var_t::@221 entries
#define ast_assert(a)
Definition utils.h:779

References ao2_cleanup, ao2_lock, ao2_unlock, ast_assert, AST_LIST_TRAVERSE, ast_log, AST_LOG_ERROR, ast_str_append(), ast_str_reset(), ast_strlen_zero(), ast_var_name(), ast_var_value(), buf, CDR_ENABLED, cdr_object_format_property(), cdr_object_get_by_name(), cdr_readonly_vars, ast_var_t::entries, is_cdr_flag_set(), LOG_ERROR, cdr_object::next, cdr_object::party_a, S_OR, cdr_object::start, total, var, and cdr_object_snapshot::variables.

Referenced by handle_showchan().

◆ ast_cdr_set_config()

void ast_cdr_set_config ( struct ast_cdr_config *  config)

Set the current CDR configuration.

Since
12
Parameters
configThe new CDR configuration

Definition at line 2978 of file cdr.c.

2979{
2980 struct module_config *mod_cfg;
2981
2982 if (!config) {
2983 return;
2984 }
2985
2986 mod_cfg = ao2_global_obj_ref(module_configs);
2987 if (!mod_cfg) {
2988 return;
2989 }
2990
2991 ao2_replace(mod_cfg->general, config);
2992
2993 cdr_set_debug_mode(mod_cfg);
2995
2996 ao2_cleanup(mod_cfg);
2997}
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition astobj2.h:501
#define cdr_set_debug_mode(mod_cfg)
Definition cdr.c:306
static int cdr_toggle_runtime_options(void)
Checks if CDRs are enabled and enables/disables the necessary options.
Definition cdr.c:4645
static const char config[]

References ao2_cleanup, ao2_global_obj_ref, ao2_replace, cdr_set_debug_mode, cdr_toggle_runtime_options(), config, and module_config::general.

Referenced by test_cdr_cleanup_cb().

◆ ast_cdr_set_property()

int ast_cdr_set_property ( const char *  channel_name,
enum ast_cdr_options  option 
)

Set a property on a CDR for a channel.

Since
12

This function sets specific administrative properties on a CDR for a channel. This includes properties like preventing a CDR from being dispatched, to setting the channel as the preferred Party A in future CDRs. See ast_cdr_options for more information.

Parameters
channel_nameThe CDR's channel
optionOption to apply to the CDR
Return values
0on success
1on error

Definition at line 3701 of file cdr.c.

3702{
3703 struct cdr_object *cdr;
3704 struct cdr_object *it_cdr;
3705
3706 cdr = cdr_object_get_by_name(channel_name);
3707 if (!cdr) {
3708 return -1;
3709 }
3710
3711 ao2_lock(cdr);
3712 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3713 if (it_cdr->fn_table == &finalized_state_fn_table) {
3714 continue;
3715 }
3716 /* Note: in general, set the flags on both the CDR record as well as the
3717 * Party A. Sometimes all we have is the Party A to look at.
3718 */
3719 ast_set_flag(&it_cdr->flags, option);
3720 ast_set_flag(&it_cdr->party_a, option);
3721 }
3722 ao2_unlock(cdr);
3723
3724 ao2_cleanup(cdr);
3725 return 0;
3726}
#define ast_set_flag(p, flag)
Definition utils.h:71

References ao2_cleanup, ao2_lock, ao2_unlock, ast_set_flag, cdr_object_get_by_name(), finalized_state_fn_table, cdr_object::next, and cdr_object::start.

Referenced by AST_TEST_DEFINE(), and cdr_prop_write_callback().

◆ ast_cdr_setuserfield()

void ast_cdr_setuserfield ( const char *  channel_name,
const char *  userfield 
)

Set CDR user field for channel (stored in CDR)

Parameters
channel_nameThe name of the channel that owns the CDR
userfieldThe user field to set

Definition at line 3630 of file cdr.c.

3631{
3632 struct cdr_object *cdr;
3633 struct party_b_userfield_update party_b_info = {
3635 .userfield = userfield,
3636 };
3637 struct cdr_object *it_cdr;
3638
3639 /* Handle Party A */
3640 cdr = cdr_object_get_by_name(channel_name);
3641 if (cdr) {
3642 ao2_lock(cdr);
3643 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3644 if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3645 continue;
3646 }
3647 ast_copy_string(it_cdr->party_a.userfield, userfield,
3648 sizeof(it_cdr->party_a.userfield));
3649 }
3650 ao2_unlock(cdr);
3651 }
3652
3653 /* Handle Party B */
3656 &party_b_info);
3657
3658 ao2_cleanup(cdr);
3659}
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition astobj2.h:1723
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, void *data, int flags)
Callback used to update the userfield on Party B on all CDRs.
Definition cdr.c:3608
static struct ao2_container * active_cdrs_all
A container of all active CDRs with a Party B indexed by Party B channel name.
Definition cdr.c:472
const char * userfield
Definition cdr.c:3604
const char * channel_name
Definition cdr.c:3603

References active_cdrs_all, ao2_callback_data, ao2_cleanup, ao2_lock, ao2_unlock, ast_copy_string(), cdr_object_get_by_name(), cdr_object_update_party_b_userfield_cb(), party_b_userfield_update::channel_name, finalized_state_fn_table, cdr_object::next, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_SEARCH_KEY, cdr_object::start, and party_b_userfield_update::userfield.

Referenced by AST_TEST_DEFINE(), and cdr_write_callback().

◆ ast_cdr_setvar()

int ast_cdr_setvar ( const char *  channel_name,
const char *  name,
const char *  value 
)

Set a variable on a CDR.

Since
12
Parameters
channel_nameThe channel to set the variable on
nameThe name of the variable to set
valueThe value of the variable to set
Return values
0on success
non-zeroon failure

Definition at line 3321 of file cdr.c.

3322{
3323 struct cdr_object *cdr;
3324 struct cdr_object *it_cdr;
3325 struct ao2_iterator *it_cdrs;
3326 char *arg = ast_strdupa(channel_name);
3327 int x;
3328
3329 for (x = 0; cdr_readonly_vars[x]; x++) {
3330 if (!strcasecmp(name, cdr_readonly_vars[x])) {
3331 ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!\n", name);
3332 return -1;
3333 }
3334 }
3335
3337 if (!it_cdrs) {
3338 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3339 return -1;
3340 }
3341
3342 for (; (cdr = ao2_iterator_next(it_cdrs)); ao2_unlock(cdr), ao2_cleanup(cdr)) {
3343 ao2_lock(cdr);
3344 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3345 struct varshead *headp = NULL;
3346
3347 if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3348 continue;
3349 }
3350 if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->base->name)) {
3351 headp = &it_cdr->party_a.variables;
3352 } else if (it_cdr->party_b.snapshot
3353 && !strcasecmp(channel_name, it_cdr->party_b.snapshot->base->name)) {
3354 headp = &it_cdr->party_b.variables;
3355 }
3356 if (headp) {
3357 set_variable(headp, name, value);
3358 }
3359 }
3360 }
3361 ao2_iterator_destroy(it_cdrs);
3362
3363 return 0;
3364}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#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
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static int cdr_object_select_all_by_name_cb(void *obj, void *arg, int flags)
Definition cdr.c:3268
static void set_variable(struct varshead *headp, const char *name, const char *value)
Definition cdr.c:1364
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
const ast_string_field name
struct ast_channel_snapshot_base * base

References active_cdrs_master, ao2_callback, ao2_cleanup, ao2_iterator_destroy(), ao2_iterator_next, ao2_lock, ao2_unlock, ast_log, AST_LOG_ERROR, ast_strdupa, ast_channel_snapshot::base, cdr_object_select_all_by_name_cb(), cdr_readonly_vars, finalized_state_fn_table, cdr_object::fn_table, LOG_ERROR, name, ast_channel_snapshot_base::name, cdr_object::next, NULL, OBJ_MULTIPLE, cdr_object::party_a, cdr_object::party_b, set_variable(), cdr_object_snapshot::snapshot, cdr_object::start, value, and cdr_object_snapshot::variables.

Referenced by AST_TEST_DEFINE(), AST_TEST_DEFINE(), and cdr_write_callback().

◆ ast_cdr_unregister()

int ast_cdr_unregister ( const char *  name)

Unregister a CDR handling engine.

Parameters
namename of CDR handler to unregister Unregisters a CDR by it's name
Return values
0The backend unregistered successfully
-1The backend could not be unregistered at this time

Definition at line 3126 of file cdr.c.

3127{
3129}

References ast_cdr_generic_unregister(), and name.

Referenced by load_module(), load_module(), reload(), tds_unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), and unregister_backend().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 4832 of file cdr.c.

◆ base_process_bridge_enter()

static enum process_bridge_enter_results base_process_bridge_enter ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel 
)
static

Definition at line 1715 of file cdr.c.

1716{
1717 /* Base process bridge enter simply indicates that we can't handle it */
1718 return BRIDGE_ENTER_NEED_CDR;
1719}

References BRIDGE_ENTER_NEED_CDR.

◆ base_process_bridge_leave()

static int base_process_bridge_leave ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel 
)
static

Definition at line 1705 of file cdr.c.

1706{
1707 return 0;
1708}

◆ base_process_dial_end()

static int base_process_dial_end ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  caller,
struct ast_channel_snapshot *  peer,
const char *  dial_status 
)
static

Definition at line 1710 of file cdr.c.

1711{
1712 return 0;
1713}

◆ base_process_parked_channel()

static int base_process_parked_channel ( struct cdr_object *  cdr,
struct ast_parked_call_payload *  parking_info 
)
static

Definition at line 1721 of file cdr.c.

1722{
1723 char park_info[128];
1724
1725 ast_assert(!strcasecmp(parking_info->parkee->base->name, cdr->party_a.snapshot->base->name));
1726
1727 /* Update Party A information regardless */
1728 cdr->fn_table->process_party_a(cdr, parking_info->parkee);
1729
1730 /* Fake out where we're parked */
1731 ast_string_field_set(cdr, appl, "Park");
1732 snprintf(park_info, sizeof(park_info), "%s:%u", parking_info->parkinglot, parking_info->parkingspace);
1733 ast_string_field_set(cdr, data, park_info);
1734
1735 /* Prevent any further changes to the App/Data fields for this record */
1737
1738 return 0;
1739}
unsigned int parkingspace
Definition parking.h:65
const ast_string_field parkinglot
Definition parking.h:69
struct ast_channel_snapshot * parkee
Definition parking.h:60
int(*const process_party_a)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Process a Party A update for the cdr_object.
Definition cdr.c:541

References ast_assert, AST_CDR_LOCK_APP, ast_set_flag, ast_string_field_set, ast_channel_snapshot::base, cdr_object::flags, cdr_object::fn_table, ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object_fn_table::process_party_a, cdr_object_snapshot::snapshot, and ast_cdr::start.

◆ base_process_party_a()

static int base_process_party_a ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  snapshot 
)
static

Definition at line 1644 of file cdr.c.

1645{
1646 ast_assert(strcasecmp(snapshot->base->name, cdr->party_a.snapshot->base->name) == 0);
1647
1648 /* Finalize the CDR if we're in hangup logic and we're set to do so */
1652 return 0;
1653 }
1654
1655 /*
1656 * Only record the context and extension if we aren't in a subroutine, or if
1657 * we are executing hangup logic.
1658 */
1661 if (strcmp(cdr->context, snapshot->dialplan->context)) {
1662 ast_string_field_set(cdr, context, snapshot->dialplan->context);
1663 }
1664 if (strcmp(cdr->exten, snapshot->dialplan->exten)) {
1665 ast_string_field_set(cdr, exten, snapshot->dialplan->exten);
1666 }
1667 }
1668
1669 cdr_object_swap_snapshot(&cdr->party_a, snapshot);
1670
1671 /* When Party A is originated to an application and the application exits, the stack
1672 * will attempt to clear the application and restore the dummy originate application
1673 * of "AppDialX". Prevent that, and any other application changes we might not want
1674 * here.
1675 */
1677 && !ast_strlen_zero(snapshot->dialplan->appl)
1678 && (strncasecmp(snapshot->dialplan->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
1679 if (strcmp(cdr->appl, snapshot->dialplan->appl)) {
1680 ast_string_field_set(cdr, appl, snapshot->dialplan->appl);
1681 }
1682 if (strcmp(cdr->data, snapshot->dialplan->data)) {
1683 ast_string_field_set(cdr, data, snapshot->dialplan->data);
1684 }
1685
1686 /* Dial (app_dial) is a special case. Because pre-dial handlers, which
1687 * execute before the dial begins, will alter the application/data to
1688 * something people typically don't want to see, if we see a channel enter
1689 * into Dial here, we set the appl/data accordingly and lock it.
1690 */
1691 if (!strcmp(snapshot->dialplan->appl, "Dial")) {
1693 }
1694 }
1695
1696 if (strcmp(cdr->linkedid, snapshot->peer->linkedid)) {
1697 ast_string_field_set(cdr, linkedid, snapshot->peer->linkedid);
1698 }
1701
1702 return 0;
1703}
static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Swap an old cdr_object_snapshot's ast_channel_snapshot for a new ast_channel_snapshot.
Definition cdr.c:1635
static void cdr_object_check_party_a_hangup(struct cdr_object *cdr)
Check to see if a CDR needs to move to the finalized state because its Party A hungup.
Definition cdr.c:1581
@ CDR_END_BEFORE_H_EXTEN
Definition cdr.h:224
@ AST_FLAG_SUBROUTINE_EXEC
Definition channel.h:1078
@ AST_SOFTHANGUP_HANGUP_EXEC
Definition channel.h:1174
const ast_string_field data
const ast_string_field context
const ast_string_field exten
const ast_string_field appl
struct ast_channel_snapshot_dialplan * dialplan
struct ast_channel_snapshot_peer * peer
struct ast_flags softhangup_flags
struct ast_flags flags
const ast_string_field linkedid
Definition cdr.c:839
const ast_string_field data
Definition cdr.c:839
const ast_string_field context
Definition cdr.c:839
const ast_string_field exten
Definition cdr.c:839
const ast_string_field appl
Definition cdr.c:839

References ast_channel_snapshot_dialplan::appl, cdr_object::appl, ast_assert, AST_CDR_LOCK_APP, AST_FLAG_SUBROUTINE_EXEC, ast_set_flag, AST_SOFTHANGUP_HANGUP_EXEC, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_channel_snapshot::base, CDR_END_BEFORE_H_EXTEN, cdr_object_check_party_a_answer(), cdr_object_check_party_a_hangup(), cdr_object_finalize(), cdr_object_swap_snapshot(), ast_channel_snapshot_dialplan::context, cdr_object::context, ast_channel_snapshot_dialplan::data, cdr_object::data, ast_channel_snapshot::dialplan, ast_channel_snapshot_dialplan::exten, cdr_object::exten, ast_channel_snapshot::flags, cdr_object::flags, is_cdr_flag_set(), ast_cdr::linkedid, ast_channel_snapshot_peer::linkedid, cdr_object::linkedid, ast_channel_snapshot_base::name, cdr_object::party_a, ast_channel_snapshot::peer, cdr_object_snapshot::snapshot, ast_channel_snapshot::softhangup_flags, and ast_cdr::start.

Referenced by dialed_pending_state_process_party_a(), and single_state_process_dial_begin().

◆ bridge_candidate_add_to_cdr()

static void bridge_candidate_add_to_cdr ( struct cdr_object *  cdr,
struct cdr_object_snapshot *  party_b 
)
static

Definition at line 2611 of file cdr.c.

2613{
2614 struct cdr_object *new_cdr;
2615
2617 if (!new_cdr) {
2618 return;
2619 }
2625 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2626 new_cdr, new_cdr->party_a.snapshot->base->name,
2628}
struct cdr_object_fn_table bridge_state_fn_table
The virtual table for the Bridged state.
Definition cdr.c:763
static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src)
Copy a snapshot and its details.
Definition cdr.c:896
const ast_string_field bridge
Definition cdr.c:839

References ast_string_field_set, ast_channel_snapshot::base, cdr_object::bridge, bridge_state_fn_table, cdr_all_relink(), CDR_DEBUG, cdr_object_check_party_a_answer(), cdr_object_create_and_append(), cdr_object_snapshot_copy(), cdr_object_transition_state(), cdr_object::lastevent, ast_channel_snapshot_base::name, cdr_object::party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by bridge_candidate_process().

◆ bridge_candidate_process()

static void bridge_candidate_process ( struct cdr_object *  cdr,
struct cdr_object *  base_cand_cdr 
)
static

Process a single bridge_candidate.

When a CDR enters a bridge, it needs to make pairings with everyone else that it is not currently paired with. This function determines, for the CDR for the channel that entered the bridge and the CDR for every other channel currently in the bridge, who is Party A and makes new CDRs.

Parameters
cdrThe cdr_object being processed
base_cand_cdrThe cdr_object that is a candidate

Definition at line 2642 of file cdr.c.

2643{
2644 struct cdr_object_snapshot *party_a;
2645 struct cdr_object *cand_cdr;
2646
2648
2649 for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->next) {
2650 /* Skip any records that are not in this bridge */
2651 if (strcmp(cand_cdr->bridge, cdr->bridge)) {
2652 continue;
2653 }
2654
2655 /* If the candidate is us or someone we've taken on, pass on by */
2656 if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)
2657 || (cdr->party_b.snapshot
2658 && !strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name))) {
2659 break;
2660 }
2661
2662 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
2663 /* We're party A - make a new CDR, append it to us, and set the candidate as
2664 * Party B */
2666 bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
2667 break;
2668 }
2669
2670 /* We're Party B. Check if we can add ourselves immediately or if we need
2671 * a new CDR for them (they already have a Party B) */
2672 if (cand_cdr->party_b.snapshot
2673 && strcasecmp(cand_cdr->party_b.snapshot->base->name, cdr->party_a.snapshot->base->name)) {
2675 } else {
2676 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2677 cand_cdr, cand_cdr->party_a.snapshot->base->name,
2678 cdr->party_a.snapshot->base->name);
2679 cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
2681 /* It's possible that this joined at one point and was never chosen
2682 * as party A. Clear their end time, as it would be set in such a
2683 * case.
2684 */
2685 memset(&cand_cdr->end, 0, sizeof(cand_cdr->end));
2686 }
2687
2688 break;
2689 }
2690
2692}
static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, struct cdr_object_snapshot *party_b)
Definition cdr.c:2611
static struct cdr_object_snapshot * cdr_object_pick_party_a(struct cdr_object_snapshot *left, struct cdr_object_snapshot *right)
Given two CDR snapshots, figure out who should be Party A for the resulting CDR.
Definition cdr.c:1294
A wrapper object around a snapshot. Fields that are mutable by the CDR engine are replicated here.
Definition cdr.c:808

References ao2_lock, ao2_unlock, ast_channel_snapshot::base, cdr_object::bridge, bridge_candidate_add_to_cdr(), cdr_all_relink(), CDR_DEBUG, cdr_object_pick_party_a(), cdr_object_snapshot_copy(), ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by handle_bridge_pairings().

◆ bridge_state_process_bridge_leave()

static int bridge_state_process_bridge_leave ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel 
)
static

Definition at line 2125 of file cdr.c.

2126{
2127 if (strcmp(cdr->bridge, bridge->uniqueid)) {
2128 return 1;
2129 }
2130 if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)
2131 && cdr->party_b.snapshot
2132 && strcasecmp(cdr->party_b.snapshot->base->name, channel->base->name)) {
2133 return 1;
2134 }
2136
2137 return 0;
2138}
const ast_string_field uniqueid
Definition bridge.h:332

References ast_channel_snapshot::base, cdr_object::bridge, cdr_object_transition_state(), finalized_state_fn_table, ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

◆ bridge_state_process_party_b()

static void bridge_state_process_party_b ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  snapshot 
)
static

◆ cdr_all_cmp_fn()

static int cdr_all_cmp_fn ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1018 of file cdr.c.

1019{
1020 struct cdr_object *left = obj;
1021 struct cdr_object *right = arg;
1022 const char *right_key = arg;
1023 int cmp;
1024
1025 switch (flags & OBJ_SEARCH_MASK) {
1026 case OBJ_SEARCH_OBJECT:
1027 right_key = right->party_b_name;
1028 /* Fall through */
1029 case OBJ_SEARCH_KEY:
1031 break;
1033 /*
1034 * We could also use a partial key struct containing a length
1035 * so strlen() does not get called for every comparison instead.
1036 */
1038 break;
1039 default:
1040 /* Sort can only work on something with a full or partial key. */
1041 ast_assert(0);
1042 cmp = 0;
1043 break;
1044 }
1045 return cmp ? 0 : CMP_MATCH;
1046}
@ CMP_MATCH
Definition astobj2.h:1027
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition astobj2.h:1087
@ OBJ_SEARCH_MASK
Search option field mask.
Definition astobj2.h:1072
const ast_string_field party_b_name
Definition cdr.c:839

References ast_assert, CMP_MATCH, cdr_object::flags, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, OBJ_SEARCH_PARTIAL_KEY, cdr_object::party_b_name, and cdr_object::start.

Referenced by load_module().

◆ cdr_all_hash_fn()

static int cdr_all_hash_fn ( const void *  obj,
const int  flags 
)
static

Definition at line 994 of file cdr.c.

995{
996 const struct cdr_object *cdr;
997 const char *key;
998
999 switch (flags & OBJ_SEARCH_MASK) {
1000 case OBJ_SEARCH_KEY:
1001 key = obj;
1002 break;
1003 case OBJ_SEARCH_OBJECT:
1004 cdr = obj;
1005 key = cdr->party_b_name;
1006 break;
1007 default:
1008 ast_assert(0);
1009 return 0;
1010 }
1011 return ast_str_case_hash(key);
1012}
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition strings.h:1303

References ast_assert, ast_str_case_hash(), cdr_object::flags, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and cdr_object::party_b_name.

Referenced by load_module().

◆ cdr_all_print_fn()

static void cdr_all_print_fn ( void *  v_obj,
void *  where,
ao2_prnt_fn *  prnt 
)
static

Definition at line 4629 of file cdr.c.

4630{
4631 struct cdr_object *cdr = v_obj;
4632
4633 if (!cdr) {
4634 return;
4635 }
4636 prnt(where, "Party A: %s; Party B: %s; Bridge %s",
4637 cdr->party_a.snapshot->base->name,
4638 cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<unknown>",
4639 cdr->bridge);
4640}

References ast_channel_snapshot::base, cdr_object::bridge, ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by load_module().

◆ cdr_all_relink()

static void cdr_all_relink ( struct cdr_object *  cdr)
static

Definition at line 1053 of file cdr.c.

1054{
1056 if (cdr->party_b.snapshot) {
1057 if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->base->name)) {
1059 ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->base->name);
1061 }
1062 } else {
1064 ast_string_field_set(cdr, party_b_name, "");
1065 }
1067}
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition astobj2.h:1600
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition astobj2.h:1554
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063

References active_cdrs_all, ao2_link_flags, ao2_lock, ao2_unlink_flags, ao2_unlock, ast_string_field_set, ast_channel_snapshot::base, ast_channel_snapshot_base::name, OBJ_NOLOCK, cdr_object::party_b, cdr_object::party_b_name, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by ast_cdr_fork(), bridge_candidate_add_to_cdr(), bridge_candidate_process(), single_state_bridge_enter_comparison(), and single_state_process_dial_begin().

◆ cdr_all_unlink()

static void cdr_all_unlink ( struct cdr_object *  cdr)
static

Definition at line 1074 of file cdr.c.

1075{
1076 struct cdr_object *cur;
1077 struct cdr_object *next;
1078
1079 ast_assert(cdr->is_root);
1080
1081 /* Hold a ref to the root CDR to ensure the list members don't go away on us. */
1082 ao2_ref(cdr, +1);
1084 for (cur = cdr; cur; cur = next) {
1085 next = cur->next;
1087 /*
1088 * It is safe to still use cur after unlinking because the
1089 * root CDR holds a ref to all the CDRs in the list and we
1090 * have a ref to the root CDR.
1091 */
1093 }
1095 ao2_ref(cdr, -1);
1096}
int is_root
Definition cdr.c:842

References active_cdrs_all, ao2_lock, ao2_ref, ao2_unlink_flags, ao2_unlock, ast_assert, ast_string_field_set, cdr_object::is_root, cdr_object::next, OBJ_NOLOCK, and cdr_object::party_b_name.

Referenced by cdr_object_dispatch_all_cb(), and handle_channel_snapshot_update_message().

◆ cdr_detach()

static void cdr_detach ( struct ast_cdr *  cdr)
static

Definition at line 3994 of file cdr.c.

3995{
3996 struct cdr_batch_item *newtail;
3997 int curr;
3998 RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
3999 int submit_batch = 0;
4000
4001 if (!cdr) {
4002 return;
4003 }
4004
4005 /* maybe they disabled CDR stuff completely, so just drop it */
4006 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4007 ast_debug(1, "Dropping CDR !\n");
4009 return;
4010 }
4011
4012 /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
4013 if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4014 post_cdr(cdr);
4016 return;
4017 }
4018
4019 /* otherwise, each CDR gets put into a batch list (at the end) */
4020 ast_debug(1, "CDR detaching from this thread\n");
4021
4022 /* we'll need a new tail for every CDR */
4023 if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
4024 post_cdr(cdr);
4026 return;
4027 }
4028
4029 /* don't traverse a whole list (just keep track of the tail) */
4031 if (!batch)
4032 init_batch();
4033 if (!batch->head) {
4034 /* new batch is empty, so point the head at the new tail */
4035 batch->head = newtail;
4036 } else {
4037 /* already got a batch with something in it, so just append a new tail */
4038 batch->tail->next = newtail;
4039 }
4040 newtail->cdr = cdr;
4041 batch->tail = newtail;
4042 curr = batch->size++;
4043
4044 /* if we have enough stuff to post, then do it */
4045 if (curr >= (mod_cfg->general->batch_settings.size - 1)) {
4046 submit_batch = 1;
4047 }
4049
4050 /* Don't submit a batch with cdr_batch_lock held */
4051 if (submit_batch) {
4053 }
4054}
void ast_cdr_free(struct ast_cdr *cdr)
Free a CDR record.
Definition cdr.c:3562
static ast_mutex_t cdr_batch_lock
Lock protecting modifications to the batch queue.
Definition cdr.c:462
static struct cdr_batch * batch
static int init_batch(void)
Definition cdr.c:3891
static void start_batch_mode(void)
Definition cdr.c:3978
static void post_cdr(struct ast_cdr *cdr)
Definition cdr.c:3661
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_mutex_lock(a)
Definition lock.h:196
Queued CDR waiting to be batched.
Definition cdr.c:440
struct ast_cdr * cdr
Definition cdr.c:441
struct cdr_batch_item * next
Definition cdr.c:442
int size
Definition cdr.c:447
struct cdr_batch_item * head
Definition cdr.c:448
struct cdr_batch_item * tail
Definition cdr.c:449

References ao2_cleanup, ao2_global_obj_ref, ast_calloc, ast_cdr_free(), ast_debug, ast_mutex_lock, ast_mutex_unlock, ast_test_flag, batch, cdr_batch_item::cdr, cdr_batch_lock, CDR_BATCHMODE, CDR_ENABLED, cdr_batch::head, init_batch(), cdr_batch_item::next, post_cdr(), RAII_VAR, cdr_batch::size, start_batch_mode(), and cdr_batch::tail.

Referenced by cdr_object_dispatch().

◆ cdr_enable_batch_mode()

static void cdr_enable_batch_mode ( struct ast_cdr_config *  config)
static

Definition at line 4577 of file cdr.c.

4578{
4579 /* Only create the thread level portions once */
4583 ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
4584 return;
4585 }
4586 }
4587
4588 /* Start the batching process */
4590
4591 ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %u or time %u seconds.\n",
4592 config->batch_settings.size, config->batch_settings.time);
4593}
static pthread_t cdr_thread
Definition cdr.c:459
static ast_cond_t cdr_pending_cond
Definition cdr.c:466
static void * do_cdr(void *data)
Definition cdr.c:4056
#define LOG_NOTICE
#define AST_PTHREADT_NULL
Definition lock.h:73
#define ast_cond_init(cond, attr)
Definition lock.h:208
#define ast_pthread_create_background(a, b, c, d)
Definition utils.h:632

References ast_cond_init, ast_log, ast_pthread_create_background, AST_PTHREADT_NULL, cdr_pending_cond, cdr_thread, config, do_cdr(), LOG_ERROR, LOG_NOTICE, NULL, and start_batch_mode().

Referenced by cdr_toggle_runtime_options().

◆ cdr_engine_shutdown()

static void cdr_engine_shutdown ( void  )
static

Definition at line 4546 of file cdr.c.

4547{
4550
4552 cdr_topic = NULL;
4553
4554 STASIS_MESSAGE_TYPE_CLEANUP(cdr_sync_message_type);
4555
4561 sched = NULL;
4562 ast_free(batch);
4563 batch = NULL;
4564
4565 aco_info_destroy(&cfg_info);
4566 ao2_global_obj_release(module_configs);
4567
4568 ao2_container_unregister("cdrs_master");
4571
4572 ao2_container_unregister("cdrs_all");
4575}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition astobj2.h:859
@ OBJ_UNLINK
Definition astobj2.h:1039
static int cdr_object_dispatch_all_cb(void *obj, void *arg, int flags)
This dispatches all cdr_object. It should only be used during shutdown, so that we get billing record...
Definition cdr.c:4417
static struct ast_cli_entry cli_commands[]
Definition cdr.c:4406
static void finalize_batch_mode(void)
Definition cdr.c:4434
static struct stasis_topic * cdr_topic
The parent topic for all topics we want to aggregate for CDRs.
Definition cdr.c:487
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition sched.c:271
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1546
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.
Definition sched.c:76
#define ARRAY_LEN(a)
Definition utils.h:706

References aco_info_destroy(), active_cdrs_all, active_cdrs_master, ao2_callback, ao2_cleanup, ao2_container_unregister(), ao2_global_obj_release, ARRAY_LEN, ast_cli_unregister_multiple(), ast_free, ast_sched_context_destroy(), batch, cdr_object_dispatch_all_cb(), cdr_topic, cli_commands, finalize_batch_mode(), NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, stasis_message_router_unsubscribe_and_join(), STASIS_MESSAGE_TYPE_CLEANUP, and stasis_router.

Referenced by load_module().

◆ cdr_format_var_internal()

static const char * cdr_format_var_internal ( struct ast_cdr *  cdr,
const char *  name 
)
static

Definition at line 3156 of file cdr.c.

3157{
3158 struct ast_var_t *variables;
3159
3160 if (ast_strlen_zero(name)) {
3161 return NULL;
3162 }
3163
3164 AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
3165 if (!strcasecmp(name, ast_var_name(variables))) {
3166 return ast_var_value(variables);
3167 }
3168 }
3169
3170 return NULL;
3171}

References AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_name(), ast_var_value(), ast_var_t::entries, name, NULL, and ast_cdr::varshead.

Referenced by ast_cdr_format_var().

◆ cdr_generic_register()

static int cdr_generic_register ( struct be_list *  generic_list,
const char *  name,
const char *  desc,
ast_cdrbe  be 
)
static

Definition at line 3040 of file cdr.c.

3041{
3042 struct cdr_beitem *i;
3043 struct cdr_beitem *cur;
3044
3045 if (!name) {
3046 return -1;
3047 }
3048
3049 if (!be) {
3050 ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
3051
3052 return -1;
3053 }
3054
3055 i = ast_calloc(1, sizeof(*i));
3056 if (!i) {
3057 return -1;
3058 }
3059
3060 i->be = be;
3061 ast_copy_string(i->name, name, sizeof(i->name));
3062 ast_copy_string(i->desc, desc, sizeof(i->desc));
3063
3064 AST_RWLIST_WRLOCK(generic_list);
3065 AST_RWLIST_TRAVERSE(generic_list, cur, list) {
3066 if (!strcasecmp(name, cur->name)) {
3067 ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
3068 AST_RWLIST_UNLOCK(generic_list);
3069 ast_free(i);
3070
3071 return -1;
3072 }
3073 }
3074
3075 AST_RWLIST_INSERT_HEAD(generic_list, i, list);
3076 AST_RWLIST_UNLOCK(generic_list);
3077
3078 return 0;
3079}
#define LOG_WARNING
#define AST_RWLIST_INSERT_HEAD
ast_cdrbe be
Definition cdr.c:428
char desc[80]
Definition cdr.c:427

References ast_calloc, ast_copy_string(), ast_free, ast_log, AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, be, cdr_beitem::be, cdr_beitem::desc, desc, cdr_beitem::list, LOG_WARNING, cdr_beitem::name, and name.

Referenced by ast_cdr_modifier_register(), and ast_cdr_register().

◆ cdr_get_tv()

static void cdr_get_tv ( struct timeval  when,
const char *  fmt,
char *  buf,
int  bufsize 
)
static

Definition at line 3173 of file cdr.c.

3174{
3175 if (fmt == NULL) { /* raw mode */
3176 snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
3177 } else {
3178 buf[0] = '\0';/* Ensure the buffer is initialized. */
3179 if (when.tv_sec) {
3180 struct ast_tm tm;
3181
3182 ast_localtime(&when, &tm, NULL);
3183 ast_strftime(buf, bufsize, fmt, &tm);
3184 }
3185 }
3186}
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

References ast_localtime(), ast_strftime(), buf, and NULL.

Referenced by ast_cdr_format_var(), cdr_object_format_property(), cli_show_channel(), and cli_show_channels().

◆ cdr_master_cmp_fn()

static int cdr_master_cmp_fn ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 960 of file cdr.c.

961{
962 struct cdr_object *left = obj;
963 struct cdr_object *right = arg;
964 const char *right_key = arg;
965 int cmp;
966
967 switch (flags & OBJ_SEARCH_MASK) {
969 right_key = right->uniqueid;
970 /* Fall through */
971 case OBJ_SEARCH_KEY:
972 cmp = strcmp(left->uniqueid, right_key);
973 break;
975 /*
976 * We could also use a partial key struct containing a length
977 * so strlen() does not get called for every comparison instead.
978 */
980 break;
981 default:
982 /* Sort can only work on something with a full or partial key. */
983 ast_assert(0);
984 cmp = 0;
985 break;
986 }
987 return cmp ? 0 : CMP_MATCH;
988}
const ast_string_field uniqueid
Definition cdr.c:839

References ast_assert, CMP_MATCH, cdr_object::flags, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, OBJ_SEARCH_PARTIAL_KEY, cdr_object::start, and cdr_object::uniqueid.

Referenced by load_module().

◆ cdr_master_hash_fn()

static int cdr_master_hash_fn ( const void *  obj,
const int  flags 
)
static

Definition at line 936 of file cdr.c.

937{
938 const struct cdr_object *cdr;
939 const char *key;
940
941 switch (flags & OBJ_SEARCH_MASK) {
942 case OBJ_SEARCH_KEY:
943 key = obj;
944 break;
946 cdr = obj;
947 key = cdr->uniqueid;
948 break;
949 default:
950 ast_assert(0);
951 return 0;
952 }
953 return ast_str_case_hash(key);
954}

References ast_assert, ast_str_case_hash(), cdr_object::flags, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and cdr_object::uniqueid.

Referenced by load_module().

◆ cdr_master_print_fn()

static void cdr_master_print_fn ( void *  v_obj,
void *  where,
ao2_prnt_fn *  prnt 
)
static

Definition at line 4604 of file cdr.c.

4605{
4606 struct cdr_object *cdr = v_obj;
4607 struct cdr_object *it_cdr;
4608
4609 if (!cdr) {
4610 return;
4611 }
4612 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4613 prnt(where, "Party A: %s; Party B: %s; Bridge %s\n",
4614 it_cdr->party_a.snapshot->base->name,
4615 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<unknown>",
4616 it_cdr->bridge);
4617 }
4618}

References cdr_object::next, and cdr_object::start.

Referenced by load_module().

◆ cdr_object_alloc()

static struct cdr_object * cdr_object_alloc ( struct ast_channel_snapshot *  chan,
const struct timeval *  event_time 
)
static

cdr_object constructor

Parameters
chanThe ast_channel_snapshot that is the CDR's Party A
event_time

This implicitly sets the state of the newly created CDR to the Single state (single_state_fn_table)

Definition at line 1142 of file cdr.c.

1143{
1144 struct cdr_object *cdr;
1145
1146 ast_assert(chan != NULL);
1147
1148 cdr = ao2_alloc(sizeof(*cdr), cdr_object_dtor);
1149 if (!cdr) {
1150 return NULL;
1151 }
1152 cdr->last = cdr;
1153 if (ast_string_field_init(cdr, 64)) {
1154 ao2_cleanup(cdr);
1155 return NULL;
1156 }
1158 ast_string_field_set(cdr, name, chan->base->name);
1162 cdr->lastevent = *event_time;
1163
1164 cdr->party_a.snapshot = chan;
1165 ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
1166
1167 CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->base->name);
1168
1170
1171 return cdr;
1172}
#define ao2_t_ref(o, delta, tag)
Definition astobj2.h:460
struct cdr_object_fn_table single_state_fn_table
The virtual table for the Single state.
Definition cdr.c:677
static int global_cdr_sequence
The global sequence counter used for CDRs.
Definition cdr.c:453
static void cdr_object_dtor(void *obj)
cdr_object Destructor
Definition cdr.c:1101
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition lock.h:764
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
const ast_string_field uniqueid
unsigned int sequence
Definition cdr.c:826
enum ast_cdr_disposition disposition
Definition cdr.c:821

References ao2_alloc, ao2_cleanup, ao2_t_ref, ast_assert, ast_atomic_fetchadd_int(), AST_CDR_NULL, ast_string_field_init, ast_string_field_set, ast_channel_snapshot::base, CDR_DEBUG, cdr_object_dtor(), cdr_object_transition_state(), cdr_object::disposition, global_cdr_sequence, cdr_object::last, cdr_object::lastevent, ast_channel_snapshot_peer::linkedid, cdr_object::linkedid, name, ast_channel_snapshot_base::name, NULL, cdr_object::party_a, ast_channel_snapshot::peer, cdr_object::sequence, single_state_fn_table, cdr_object_snapshot::snapshot, ast_channel_snapshot_base::uniqueid, and cdr_object::uniqueid.

Referenced by cdr_object_create_and_append(), and handle_channel_snapshot_update_message().

◆ cdr_object_check_party_a_answer()

static void cdr_object_check_party_a_answer ( struct cdr_object *  cdr)
static

Check to see if a CDR needs to be answered based on its Party A. Note that this is safe to call as much as you want - we won't answer twice.

Definition at line 1598 of file cdr.c.

1599{
1600 if (cdr->party_a.snapshot->state == AST_STATE_UP && ast_tvzero(cdr->answer)) {
1601 cdr->answer = cdr->lastevent;
1602 /* tv_usec is suseconds_t, which could be int or long */
1603 CDR_DEBUG("%p - Set answered time to %ld.%06ld\n", cdr,
1604 (long)cdr->answer.tv_sec,
1605 (long)cdr->answer.tv_usec);
1606 }
1607}

References cdr_object::answer, AST_STATE_UP, ast_tvzero(), CDR_DEBUG, cdr_object::lastevent, cdr_object::party_a, cdr_object_snapshot::snapshot, and ast_channel_snapshot::state.

Referenced by ast_cdr_reset(), base_process_party_a(), bridge_candidate_add_to_cdr(), and single_state_init_function().

◆ cdr_object_check_party_a_hangup()

static void cdr_object_check_party_a_hangup ( struct cdr_object *  cdr)
static

◆ cdr_object_create_and_append()

static struct cdr_object * cdr_object_create_and_append ( struct cdr_object *  cdr,
const struct timeval *  event_time 
)
static

Create a new cdr_object and append it to an existing chain.

Parameters
cdrThe cdr_object to append to
event_time

Definition at line 1179 of file cdr.c.

1180{
1181 struct cdr_object *new_cdr;
1182 struct cdr_object *it_cdr;
1183 struct cdr_object *cdr_last;
1184
1185 cdr_last = cdr->last;
1186 new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot, event_time);
1187 if (!new_cdr) {
1188 return NULL;
1189 }
1190 new_cdr->disposition = AST_CDR_NULL;
1191
1192 /* Copy over the linkedid, as it may have changed */
1198
1199 /*
1200 * If the current CDR says to disable all future ones,
1201 * keep the disable chain going
1202 */
1205 }
1206
1207 /* Copy over other Party A information */
1208 cdr_object_snapshot_copy(&new_cdr->party_a, &cdr_last->party_a);
1209
1210 /* Append the CDR to the end of the list */
1211 for (it_cdr = cdr; it_cdr->next; it_cdr = it_cdr->next) {
1212 it_cdr->last = new_cdr;
1213 }
1214 it_cdr->last = new_cdr;
1215 it_cdr->next = new_cdr;
1216
1217 return new_cdr;
1218}
static struct cdr_object * cdr_object_alloc(struct ast_channel_snapshot *chan, const struct timeval *event_time)
cdr_object constructor
Definition cdr.c:1142
@ AST_CDR_FLAG_DISABLE_ALL
Definition cdr.h:246

References cdr_object::appl, AST_CDR_FLAG_DISABLE_ALL, AST_CDR_NULL, ast_set_flag, ast_string_field_set, ast_test_flag, cdr_object_alloc(), cdr_object_snapshot_copy(), cdr_object::context, cdr_object::data, cdr_object::exten, cdr_object::last, cdr_object::linkedid, cdr_object::next, NULL, and cdr_object::start.

Referenced by ast_cdr_fork(), bridge_candidate_add_to_cdr(), handle_channel_snapshot_update_message(), handle_dial_message(), handle_parked_call_message(), handle_parking_bridge_enter_message(), and handle_standard_bridge_enter_message().

◆ cdr_object_create_public_records()

static struct ast_cdr * cdr_object_create_public_records ( struct cdr_object *  cdr)
static

Create a chain of ast_cdr objects from a chain of cdr_object suitable for consumption by the registered CDR backends.

Parameters
cdrThe cdr_object to convert to a public record
Returns
A chain of ast_cdr objects on success
Return values
NULLon failure

Definition at line 1389 of file cdr.c.

1390{
1391 struct ast_cdr *pub_cdr = NULL, *cdr_prev = NULL;
1392 struct cdr_object *it_cdr;
1393 struct ast_var_t *it_var, *it_copy_var;
1394 struct ast_channel_snapshot *party_a;
1395 struct ast_channel_snapshot *party_b;
1396
1397 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
1398 struct ast_cdr *cdr_copy;
1399
1400 /* Don't create records for CDRs where the party A was a dialed channel */
1401 if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
1402 ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
1403 it_cdr->party_a.snapshot->base->name);
1404 continue;
1405 }
1406
1407 cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
1408 if (!cdr_copy) {
1410 return NULL;
1411 }
1412
1413 party_a = it_cdr->party_a.snapshot;
1414 party_b = it_cdr->party_b.snapshot;
1415
1416 /* Party A */
1417 ast_assert(party_a != NULL);
1418 ast_copy_string(cdr_copy->accountcode, party_a->base->accountcode, sizeof(cdr_copy->accountcode));
1419 cdr_copy->amaflags = party_a->amaflags;
1420 ast_copy_string(cdr_copy->channel, party_a->base->name, sizeof(cdr_copy->channel));
1421 ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller->name, party_a->caller->number, "");
1422 ast_copy_string(cdr_copy->src, party_a->caller->number, sizeof(cdr_copy->src));
1423 ast_copy_string(cdr_copy->uniqueid, party_a->base->uniqueid, sizeof(cdr_copy->uniqueid));
1424 ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
1425 ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
1426 ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
1427 ast_copy_string(cdr_copy->dcontext, it_cdr->context, sizeof(cdr_copy->dcontext));
1428 ast_copy_string(cdr_copy->tenantid, party_a->base->tenantid, sizeof(cdr_copy->tenantid));
1429
1430 /* Party B */
1431 if (party_b) {
1432 ast_copy_string(cdr_copy->dstchannel, party_b->base->name, sizeof(cdr_copy->dstchannel));
1433 ast_copy_string(cdr_copy->peeraccount, party_b->base->accountcode, sizeof(cdr_copy->peeraccount));
1434 if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
1435 snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
1436 }
1437 ast_copy_string(cdr_copy->peertenantid, party_b->base->tenantid, sizeof(cdr_copy->peertenantid));
1438 }
1439 if (ast_strlen_zero(cdr_copy->userfield) && !ast_strlen_zero(it_cdr->party_a.userfield)) {
1440 ast_copy_string(cdr_copy->userfield, it_cdr->party_a.userfield, sizeof(cdr_copy->userfield));
1441 }
1442
1443 /* Timestamps/durations */
1444 cdr_copy->start = it_cdr->start;
1445 cdr_copy->answer = it_cdr->answer;
1446 cdr_copy->end = it_cdr->end;
1449
1450 /* Flags and IDs */
1452 ast_copy_string(cdr_copy->linkedid, it_cdr->linkedid, sizeof(cdr_copy->linkedid));
1453 cdr_copy->disposition = it_cdr->disposition;
1454 cdr_copy->sequence = it_cdr->sequence;
1455
1456 /* Variables */
1457 copy_variables(&cdr_copy->varshead, &it_cdr->party_a.variables);
1458 AST_LIST_TRAVERSE(&it_cdr->party_b.variables, it_var, entries) {
1459 int found = 0;
1460 struct ast_var_t *newvariable;
1461 AST_LIST_TRAVERSE(&cdr_copy->varshead, it_copy_var, entries) {
1462 if (!strcasecmp(ast_var_name(it_var), ast_var_name(it_copy_var))) {
1463 found = 1;
1464 break;
1465 }
1466 }
1467 if (!found && (newvariable = ast_var_assign(ast_var_name(it_var), ast_var_value(it_var)))) {
1468 AST_LIST_INSERT_TAIL(&cdr_copy->varshead, newvariable, entries);
1469 }
1470 }
1471
1472 if (!pub_cdr) {
1473 pub_cdr = cdr_copy;
1474 cdr_prev = pub_cdr;
1475 } else {
1476 cdr_prev->next = cdr_copy;
1477 cdr_prev = cdr_copy;
1478 }
1479 }
1480
1481 return pub_cdr;
1482}
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition callerid.c:1273
static long cdr_object_get_duration(struct cdr_object *cdr)
Definition cdr.c:1329
static long cdr_object_get_billsec(struct cdr_object *cdr)
Compute the billsec for a cdr_object.
Definition cdr.c:1337
static int snapshot_is_dialed(struct ast_channel_snapshot *snapshot)
Return whether or not a ast_channel_snapshot is for a channel that was created as the result of a dia...
Definition cdr.c:1281
#define ast_var_assign(name, value)
Definition chanvars.h:40
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
const ast_string_field tenantid
const ast_string_field accountcode
const ast_string_field number
const ast_string_field name
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_caller * caller
#define ast_copy_flags(dest, src, flagz)
Definition utils.h:85
#define AST_FLAGS_ALL
Definition utils.h:217

References ast_channel_snapshot_base::accountcode, ast_channel_snapshot::amaflags, ast_assert, ast_callerid_merge(), ast_calloc, ast_copy_flags, ast_copy_string(), ast_debug, AST_FLAGS_ALL, ast_free, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_assign, ast_var_name(), ast_var_value(), ast_channel_snapshot::base, ast_channel_snapshot::caller, cdr_object_get_billsec(), cdr_object_get_duration(), copy_variables(), ast_var_t::entries, ast_channel_snapshot_caller::name, ast_channel_snapshot_base::name, ast_cdr::next, cdr_object::next, NULL, ast_channel_snapshot_caller::number, snapshot_is_dialed(), ast_cdr::start, cdr_object::start, ast_channel_snapshot_base::tenantid, ast_channel_snapshot_base::uniqueid, and ast_cdr::varshead.

Referenced by cdr_object_dispatch().

◆ cdr_object_dispatch()

static void cdr_object_dispatch ( struct cdr_object *  cdr)
static

Dispatch a CDR.

Parameters
cdrThe cdr_object to dispatch

This will create a ast_cdr object and publish it to the various backends

Definition at line 1490 of file cdr.c.

1491{
1492 struct ast_cdr *pub_cdr;
1493
1494 CDR_DEBUG("%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
1495 cdr->party_a.snapshot->base->name,
1496 cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<none>");
1499}
static struct ast_cdr * cdr_object_create_public_records(struct cdr_object *cdr)
Create a chain of ast_cdr objects from a chain of cdr_object suitable for consumption by the register...
Definition cdr.c:1389
static void cdr_detach(struct ast_cdr *cdr)
Definition cdr.c:3994

References ast_channel_snapshot::base, CDR_DEBUG, cdr_detach(), cdr_object_create_public_records(), ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, and ast_cdr::start.

Referenced by cdr_object_dispatch_all_cb(), and handle_channel_snapshot_update_message().

◆ cdr_object_dispatch_all_cb()

static int cdr_object_dispatch_all_cb ( void *  obj,
void *  arg,
int  flags 
)
static

This dispatches all cdr_object. It should only be used during shutdown, so that we get billing records for everything that we can.

Definition at line 4417 of file cdr.c.

4418{
4419 struct cdr_object *cdr = obj;
4420 struct cdr_object *it_cdr;
4421
4422 ao2_lock(cdr);
4423 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4425 }
4427 ao2_unlock(cdr);
4428
4429 cdr_all_unlink(cdr);
4430
4431 return CMP_MATCH;
4432}
static void cdr_all_unlink(struct cdr_object *cdr)
Definition cdr.c:1074
static void cdr_object_dispatch(struct cdr_object *cdr)
Dispatch a CDR.
Definition cdr.c:1490

References ao2_lock, ao2_unlock, cdr_all_unlink(), cdr_object_dispatch(), cdr_object_transition_state(), CMP_MATCH, finalized_state_fn_table, cdr_object::next, and cdr_object::start.

Referenced by cdr_engine_shutdown().

◆ cdr_object_dtor()

static void cdr_object_dtor ( void *  obj)
static

cdr_object Destructor

Definition at line 1101 of file cdr.c.

1102{
1103 struct cdr_object *cdr = obj;
1104 struct ast_var_t *it_var;
1105
1108 while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_a.variables, entries))) {
1109 ast_var_delete(it_var);
1110 }
1111 while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_b.variables, entries))) {
1112 ast_var_delete(it_var);
1113 }
1115
1116 /* CDR destruction used to work by calling ao2_cleanup(next) and
1117 * allowing the chain to destroy itself neatly. Unfortunately, for
1118 * really long chains, this can result in a stack overflow. So now
1119 * when the root CDR is destroyed, it is responsible for unreffing
1120 * all CDRs in the chain
1121 */
1122 if (cdr->is_root) {
1123 struct cdr_object *curr = cdr->next;
1124 struct cdr_object *next;
1125
1126 while (curr) {
1127 next = curr->next;
1129 curr = next;
1130 }
1131 }
1132}
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object

References ao2_cleanup, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_var_delete(), ast_var_t::entries, cdr_object::is_root, cdr_object::next, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, cdr_object::start, and cdr_object_snapshot::variables.

Referenced by cdr_object_alloc().

◆ cdr_object_finalize()

static void cdr_object_finalize ( struct cdr_object *  cdr)
static

Finalize a CDR.

This function is safe to call multiple times. Note that you can call this explicitly before going to the finalized state if there's a chance the CDR will be re-activated, in which case the cdr's end time should be cleared. This function is implicitly called when a CDR transitions to the finalized state and right before it is dispatched

Parameters
cdrThe CDR to finalize

Definition at line 1544 of file cdr.c.

1545{
1546 if (!ast_tvzero(cdr->end)) {
1547 return;
1548 }
1549 cdr->end = cdr->lastevent;
1550
1551 if (cdr->disposition == AST_CDR_NULL) {
1552 if (!ast_tvzero(cdr->answer)) {
1554 } else if (cdr->party_a.snapshot->hangup->cause) {
1556 } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangup->cause) {
1558 } else {
1560 }
1561 }
1562
1563 /* tv_usec is suseconds_t, which could be int or long */
1564 ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dur %.3f bill %.3f dispo %s\n",
1565 cdr->party_a.snapshot->base->name,
1566 (long)cdr->start.tv_sec,
1567 (long)cdr->start.tv_usec,
1568 (long)cdr->answer.tv_sec,
1569 (long)cdr->answer.tv_usec,
1570 (long)cdr->end.tv_sec,
1571 (long)cdr->end.tv_usec,
1572 (double)ast_tvdiff_ms(cdr->end, cdr->start) / 1000.0,
1573 (double)ast_tvdiff_ms(cdr->end, cdr->answer) / 1000.0,
1575}
static void cdr_object_set_disposition(struct cdr_object *cdr, int hangupcause)
Set the disposition on a cdr_object based on a hangupcause code.
Definition cdr.c:1506
struct ast_channel_snapshot_hangup * hangup
struct timeval end
Definition cdr.c:824

References cdr_object::answer, AST_CDR_ANSWERED, ast_cdr_disp2str(), AST_CDR_FAILED, AST_CDR_NULL, ast_debug, ast_tvdiff_ms(), ast_tvzero(), ast_channel_snapshot::base, ast_channel_snapshot_hangup::cause, cdr_object_set_disposition(), cdr_object::disposition, cdr_object::end, ast_channel_snapshot::hangup, cdr_object::lastevent, ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by ast_cdr_fork(), base_process_party_a(), cdr_object_check_party_a_hangup(), cdr_object_finalize_party_b(), cdr_object_party_b_left_bridge_cb(), dial_state_process_bridge_enter(), finalized_state_init_function(), handle_channel_snapshot_update_message(), handle_standard_bridge_enter_message(), and single_state_bridge_enter_comparison().

◆ cdr_object_finalize_party_b()

static int cdr_object_finalize_party_b ( void *  obj,
void *  arg,
void *  data,
int  flags 
)
static

Definition at line 2324 of file cdr.c.

2325{
2326 struct cdr_object *cdr = obj;
2327
2328 if (!strcasecmp(cdr->party_b_name, arg)) {
2329#ifdef AST_DEVMODE
2330 struct ast_channel_snapshot *party_b = data;
2331
2332 /*
2333 * For sanity's sake we also assert the party_b snapshot
2334 * is consistent with the key.
2335 */
2337 && !strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name));
2338#endif
2339
2340 /* Don't transition to the finalized state - let the Party A do
2341 * that when its ready
2342 */
2344 }
2345 return 0;
2346}

References ast_assert, ast_channel_snapshot::base, cdr_object_finalize(), ast_channel_snapshot_base::name, cdr_object::party_b, cdr_object::party_b_name, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by handle_channel_snapshot_update_message().

◆ cdr_object_format_property()

static int cdr_object_format_property ( struct cdr_object *  cdr_obj,
const char *  name,
char *  value,
size_t  length 
)
static

Format one of the standard properties on a cdr_object.

Definition at line 3386 of file cdr.c.

3387{
3388 struct ast_channel_snapshot *party_a = cdr_obj->party_a.snapshot;
3389 struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
3390
3391 if (!strcasecmp(name, "clid")) {
3392 ast_callerid_merge(value, length, party_a->caller->name, party_a->caller->number, "");
3393 } else if (!strcasecmp(name, "src")) {
3394 ast_copy_string(value, party_a->caller->number, length);
3395 } else if (!strcasecmp(name, "dst")) {
3396 ast_copy_string(value, party_a->dialplan->exten, length);
3397 } else if (!strcasecmp(name, "dcontext")) {
3398 ast_copy_string(value, party_a->dialplan->context, length);
3399 } else if (!strcasecmp(name, "channel")) {
3400 ast_copy_string(value, party_a->base->name, length);
3401 } else if (!strcasecmp(name, "dstchannel")) {
3402 if (party_b) {
3403 ast_copy_string(value, party_b->base->name, length);
3404 } else {
3405 ast_copy_string(value, "", length);
3406 }
3407 } else if (!strcasecmp(name, "lastapp")) {
3408 ast_copy_string(value, party_a->dialplan->appl, length);
3409 } else if (!strcasecmp(name, "lastdata")) {
3410 ast_copy_string(value, party_a->dialplan->data, length);
3411 } else if (!strcasecmp(name, "start")) {
3412 cdr_get_tv(cdr_obj->start, NULL, value, length);
3413 } else if (!strcasecmp(name, "answer")) {
3414 cdr_get_tv(cdr_obj->answer, NULL, value, length);
3415 } else if (!strcasecmp(name, "end")) {
3416 cdr_get_tv(cdr_obj->end, NULL, value, length);
3417 } else if (!strcasecmp(name, "duration")) {
3418 snprintf(value, length, "%ld", cdr_object_get_duration(cdr_obj));
3419 } else if (!strcasecmp(name, "billsec")) {
3420 snprintf(value, length, "%ld", cdr_object_get_billsec(cdr_obj));
3421 } else if (!strcasecmp(name, "disposition")) {
3422 snprintf(value, length, "%u", cdr_obj->disposition);
3423 } else if (!strcasecmp(name, "amaflags")) {
3424 snprintf(value, length, "%d", party_a->amaflags);
3425 } else if (!strcasecmp(name, "accountcode")) {
3426 ast_copy_string(value, party_a->base->accountcode, length);
3427 } else if (!strcasecmp(name, "peeraccount")) {
3428 if (party_b) {
3429 ast_copy_string(value, party_b->base->accountcode, length);
3430 } else {
3431 ast_copy_string(value, "", length);
3432 }
3433 } else if (!strcasecmp(name, "uniqueid")) {
3434 ast_copy_string(value, party_a->base->uniqueid, length);
3435 } else if (!strcasecmp(name, "linkedid")) {
3436 ast_copy_string(value, cdr_obj->linkedid, length);
3437 } else if (!strcasecmp(name, "tenantid")) {
3438 ast_copy_string(value, party_a->base->tenantid, length);
3439 } else if (!strcasecmp(name, "peertenantid")) {
3440 if (party_b) {
3441 ast_copy_string(value, party_b->base->tenantid, length);
3442 } else {
3443 ast_copy_string(value, "", length);
3444 }
3445 } else if (!strcasecmp(name, "userfield")) {
3446 ast_copy_string(value, cdr_obj->party_a.userfield, length);
3447 } else if (!strcasecmp(name, "sequence")) {
3448 snprintf(value, length, "%u", cdr_obj->sequence);
3449 } else {
3450 return 1;
3451 }
3452
3453 return 0;
3454}

References ast_channel_snapshot_base::accountcode, ast_channel_snapshot::amaflags, cdr_object::answer, ast_channel_snapshot_dialplan::appl, ast_callerid_merge(), ast_copy_string(), ast_channel_snapshot::base, ast_channel_snapshot::caller, cdr_get_tv(), cdr_object_get_billsec(), cdr_object_get_duration(), ast_channel_snapshot_dialplan::context, ast_channel_snapshot_dialplan::data, ast_channel_snapshot::dialplan, cdr_object::disposition, cdr_object::end, ast_channel_snapshot_dialplan::exten, cdr_object::linkedid, name, ast_channel_snapshot_caller::name, ast_channel_snapshot_base::name, NULL, ast_channel_snapshot_caller::number, cdr_object::party_a, cdr_object::party_b, cdr_object::sequence, cdr_object_snapshot::snapshot, cdr_object::start, ast_channel_snapshot_base::tenantid, ast_channel_snapshot_base::uniqueid, cdr_object_snapshot::userfield, and value.

Referenced by ast_cdr_getvar(), and ast_cdr_serialize_variables().

◆ cdr_object_format_var_internal()

static void cdr_object_format_var_internal ( struct cdr_object *  cdr,
const char *  name,
char *  value,
size_t  length 
)
static

Format a variable on a cdr_object.

Definition at line 3369 of file cdr.c.

3370{
3371 struct ast_var_t *variable;
3372
3373 AST_LIST_TRAVERSE(&cdr->party_a.variables, variable, entries) {
3374 if (!strcasecmp(name, ast_var_name(variable))) {
3375 ast_copy_string(value, ast_var_value(variable), length);
3376 return;
3377 }
3378 }
3379
3380 *value = '\0';
3381}

References ast_copy_string(), AST_LIST_TRAVERSE, ast_var_name(), ast_var_value(), ast_var_t::entries, name, cdr_object::party_a, value, and cdr_object_snapshot::variables.

Referenced by ast_cdr_getvar().

◆ cdr_object_get_billsec()

static long cdr_object_get_billsec ( struct cdr_object *  cdr)
static

Compute the billsec for a cdr_object.

Definition at line 1337 of file cdr.c.

1338{
1339 long int ms;
1340
1341 if (ast_tvzero(cdr->answer)) {
1342 return 0;
1343 }
1344
1345 ms = ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->answer);
1346 if (ms % 1000 >= 500
1348 ms = (ms / 1000) + 1;
1349 } else {
1350 ms = ms / 1000;
1351 }
1352
1353 return ms;
1354}
@ CDR_INITIATED_SECONDS
Definition cdr.h:225
char * end
Definition eagi_proxy.c:73

References cdr_object::answer, ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), CDR_INITIATED_SECONDS, cdr_object::end, and is_cdr_flag_set().

Referenced by cdr_object_create_public_records(), and cdr_object_format_property().

◆ cdr_object_get_by_name()

static struct cdr_object * cdr_object_get_by_name ( const char *  name)
static

Definition at line 3463 of file cdr.c.

3464{
3465 char *param;
3466
3467 if (ast_strlen_zero(name)) {
3468 return NULL;
3469 }
3470
3471 param = ast_strdupa(name);
3473}
static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
Definition cdr.c:3284

References active_cdrs_master, ao2_callback, ast_strdupa, ast_strlen_zero(), cdr_object_get_by_name_cb(), name, and NULL.

Referenced by ast_cdr_clear_property(), ast_cdr_fork(), ast_cdr_getvar(), ast_cdr_reset(), ast_cdr_serialize_variables(), ast_cdr_set_property(), ast_cdr_setuserfield(), and cli_show_channel().

◆ cdr_object_get_by_name_cb()

static int cdr_object_get_by_name_cb ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 3284 of file cdr.c.

3285{
3286 struct cdr_object *cdr = obj;
3287 const char *name = arg;
3288
3289 if (!strcasecmp(cdr->party_a.snapshot->base->name, name)) {
3290 return CMP_MATCH;
3291 }
3292 return 0;
3293}

References ast_channel_snapshot::base, CMP_MATCH, name, ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by cdr_object_get_by_name().

◆ cdr_object_get_duration()

static long cdr_object_get_duration ( struct cdr_object *  cdr)
static

Compute the duration for a cdr_object

Definition at line 1329 of file cdr.c.

1330{
1331 return (long)(ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->start) / 1000);
1332}

References ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), cdr_object::end, and cdr_object::start.

Referenced by cdr_object_create_public_records(), and cdr_object_format_property().

◆ cdr_object_party_b_left_bridge_cb()

static int cdr_object_party_b_left_bridge_cb ( void *  obj,
void *  arg,
void *  data,
int  flags 
)
static

Callback used to notify CDRs of a Party B leaving the bridge.

Definition at line 2501 of file cdr.c.

2502{
2503 struct cdr_object *cdr = obj;
2504 struct bridge_leave_data *leave_data = data;
2505
2506 if (cdr->fn_table == &bridge_state_fn_table
2507 && !strcmp(cdr->bridge, leave_data->bridge->uniqueid)
2508 && !strcasecmp(cdr->party_b_name, arg)) {
2509 /*
2510 * For sanity's sake we also assert the party_b snapshot
2511 * is consistent with the key.
2512 */
2514 && !strcasecmp(cdr->party_b.snapshot->base->name, leave_data->channel->base->name));
2515
2516 /* It is our Party B, in our bridge. Set the last event and let the handler
2517 * transition our CDR appropriately when we leave the bridge.
2518 */
2519 cdr->lastevent = *leave_data->lastevent;
2521 }
2522 return 0;
2523}
const struct timeval * lastevent
Definition cdr.c:2497
struct ast_bridge_snapshot * bridge
Definition cdr.c:2495
struct ast_channel_snapshot * channel
Definition cdr.c:2496

References ast_assert, ast_channel_snapshot::base, cdr_object::bridge, bridge_leave_data::bridge, bridge_state_fn_table, cdr_object_finalize(), bridge_leave_data::channel, cdr_object::fn_table, cdr_object::lastevent, bridge_leave_data::lastevent, ast_channel_snapshot_base::name, cdr_object::party_b, cdr_object::party_b_name, cdr_object_snapshot::snapshot, and ast_bridge_snapshot::uniqueid.

Referenced by handle_bridge_leave_message().

◆ cdr_object_pick_party_a()

static struct cdr_object_snapshot * cdr_object_pick_party_a ( struct cdr_object_snapshot *  left,
struct cdr_object_snapshot *  right 
)
static

Given two CDR snapshots, figure out who should be Party A for the resulting CDR.

Parameters
leftOne of the snapshots
rightThe other snapshot
Returns
The snapshot that won

Definition at line 1294 of file cdr.c.

1295{
1296 /* Check whether or not the party is dialed. A dialed party is never the
1297 * Party A with a party that was not dialed.
1298 */
1299 if (!snapshot_is_dialed(left->snapshot) && snapshot_is_dialed(right->snapshot)) {
1300 return left;
1301 } else if (snapshot_is_dialed(left->snapshot) && !snapshot_is_dialed(right->snapshot)) {
1302 return right;
1303 }
1304
1305 /* Try the Party A flag */
1307 return left;
1309 return right;
1310 }
1311
1312 /* Neither party is dialed and neither has the Party A flag - defer to
1313 * creation time */
1314 if (left->snapshot->base->creationtime.tv_sec < right->snapshot->base->creationtime.tv_sec) {
1315 return left;
1316 } else if (left->snapshot->base->creationtime.tv_sec > right->snapshot->base->creationtime.tv_sec) {
1317 return right;
1318 } else if (left->snapshot->base->creationtime.tv_usec > right->snapshot->base->creationtime.tv_usec) {
1319 return right;
1320 } else {
1321 /* Okay, fine, take the left one */
1322 return left;
1323 }
1324}
@ AST_CDR_FLAG_PARTY_A
Definition cdr.h:247

References AST_CDR_FLAG_PARTY_A, ast_test_flag, ast_channel_snapshot::base, ast_channel_snapshot_base::creationtime, cdr_object_snapshot::snapshot, and snapshot_is_dialed().

Referenced by bridge_candidate_process(), and single_state_bridge_enter_comparison().

◆ cdr_object_select_all_by_name_cb()

static int cdr_object_select_all_by_name_cb ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 3268 of file cdr.c.

3269{
3270 struct cdr_object *cdr = obj;
3271 const char *name = arg;
3272
3273 if (!strcasecmp(cdr->party_a.snapshot->base->name, name) ||
3274 (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->base->name, name))) {
3275 return CMP_MATCH;
3276 }
3277 return 0;
3278}

References ast_channel_snapshot::base, CMP_MATCH, name, ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by ast_cdr_setvar().

◆ cdr_object_set_disposition()

static void cdr_object_set_disposition ( struct cdr_object *  cdr,
int  hangupcause 
)
static

Set the disposition on a cdr_object based on a hangupcause code.

Parameters
cdrThe cdr_object
hangupcauseThe Asterisk hangup cause code

Definition at line 1506 of file cdr.c.

1507{
1508 /* Change the disposition based on the hang up cause */
1509 switch (hangupcause) {
1510 case AST_CAUSE_BUSY:
1512 break;
1516 } else {
1518 }
1519 break;
1523 break;
1527 break;
1528 default:
1529 break;
1530 }
1531}
#define AST_CAUSE_CONGESTION
Definition causes.h:153
#define AST_CAUSE_NO_ROUTE_DESTINATION
Definition causes.h:100
#define AST_CAUSE_UNREGISTERED
Definition causes.h:154
#define AST_CAUSE_BUSY
Definition causes.h:149
#define AST_CAUSE_NO_ANSWER
Definition causes.h:109
#define AST_CAUSE_NORMAL_CLEARING
Definition causes.h:106
@ CDR_CONGESTION
Definition cdr.h:223

References AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NO_ANSWER, AST_CAUSE_NO_ROUTE_DESTINATION, AST_CAUSE_NORMAL_CLEARING, AST_CAUSE_UNREGISTERED, AST_CDR_BUSY, AST_CDR_CONGESTION, AST_CDR_FAILED, AST_CDR_NOANSWER, CDR_CONGESTION, cdr_object::disposition, and is_cdr_flag_set().

Referenced by cdr_object_finalize().

◆ cdr_object_snapshot_copy()

static void cdr_object_snapshot_copy ( struct cdr_object_snapshot *  dst,
struct cdr_object_snapshot *  src 
)
static

Copy a snapshot and its details.

Parameters
dstThe destination
srcThe source

Definition at line 896 of file cdr.c.

897{
898 ao2_t_replace(dst->snapshot, src->snapshot, "CDR snapshot copy");
899 strcpy(dst->userfield, src->userfield);
900 dst->flags = src->flags;
901 copy_variables(&dst->variables, &src->variables);
902}
#define ao2_t_replace(dst, src, tag)
Definition astobj2.h:504

References ao2_t_replace, copy_variables(), cdr_object_snapshot::flags, cdr_object_snapshot::snapshot, cdr_object_snapshot::userfield, and cdr_object_snapshot::variables.

Referenced by bridge_candidate_add_to_cdr(), bridge_candidate_process(), cdr_object_create_and_append(), dial_state_process_bridge_enter(), and single_state_bridge_enter_comparison().

◆ cdr_object_swap_snapshot()

static void cdr_object_swap_snapshot ( struct cdr_object_snapshot *  old_snapshot,
struct ast_channel_snapshot *  new_snapshot 
)
static

Swap an old cdr_object_snapshot's ast_channel_snapshot for a new ast_channel_snapshot.

Parameters
old_snapshotThe old cdr_object_snapshot
new_snapshotThe new ast_channel_snapshot for old_snapshot

Definition at line 1635 of file cdr.c.

1637{
1638 cdr_object_update_cid(old_snapshot, new_snapshot);
1639 ao2_t_replace(old_snapshot->snapshot, new_snapshot, "Swap CDR snapshot");
1640}
static void cdr_object_update_cid(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Set Caller ID information on a CDR.
Definition cdr.c:1610

References ao2_t_replace, cdr_object_update_cid(), and cdr_object_snapshot::snapshot.

Referenced by base_process_party_a(), bridge_state_process_party_b(), dial_state_process_dial_end(), dial_state_process_party_b(), and single_state_process_dial_begin().

◆ cdr_object_transition_state()

static void cdr_object_transition_state ( struct cdr_object *  cdr,
struct cdr_object_fn_table *  fn_table 
)
static

◆ cdr_object_transition_state_init()

static void cdr_object_transition_state_init ( struct cdr_object *  cdr,
struct cdr_object_fn_table *  fn_table,
int  do_init 
)
static

Transition a cdr_object to a new state with initiation flag.

Parameters
cdrThe cdr_object to transition
fn_tableThe cdr_object_fn_table state to go to
do_init

Definition at line 910 of file cdr.c.

911{
912 CDR_DEBUG("%p - Transitioning CDR for %s from state %s to %s\n",
913 cdr, cdr->party_a.snapshot->base->name,
914 cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
915 cdr->fn_table = fn_table;
916
917 if (cdr->fn_table->init_function && do_init) {
918 cdr->fn_table->init_function(cdr);
919 }
920}
const char * name
Name of the subclass.
Definition cdr.c:522
void(*const init_function)(struct cdr_object *cdr)
An initialization function. This will be called automatically when a cdr_object is switched to this t...
Definition cdr.c:531

References ast_channel_snapshot::base, CDR_DEBUG, cdr_object::fn_table, cdr_object_fn_table::init_function, ast_channel_snapshot_base::name, cdr_object_fn_table::name, cdr_object::party_a, and cdr_object_snapshot::snapshot.

Referenced by cdr_object_transition_state(), and dialed_pending_state_process_party_a().

◆ cdr_object_update_cid()

static void cdr_object_update_cid ( struct cdr_object_snapshot *  old_snapshot,
struct ast_channel_snapshot *  new_snapshot 
)
static

Set Caller ID information on a CDR.

Definition at line 1610 of file cdr.c.

1611{
1612 if (!old_snapshot->snapshot) {
1613 set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1614 set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1615 set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1616 return;
1617 }
1618 if (strcmp(old_snapshot->snapshot->caller->dnid, new_snapshot->caller->dnid)) {
1619 set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1620 }
1621 if (strcmp(old_snapshot->snapshot->caller->subaddr, new_snapshot->caller->subaddr)) {
1622 set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1623 }
1624 if (strcmp(old_snapshot->snapshot->caller->dialed_subaddr, new_snapshot->caller->dialed_subaddr)) {
1625 set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1626 }
1627}
const ast_string_field dialed_subaddr
const ast_string_field subaddr
const ast_string_field dnid

References ast_channel_snapshot::caller, ast_channel_snapshot_caller::dialed_subaddr, ast_channel_snapshot_caller::dnid, set_variable(), cdr_object_snapshot::snapshot, ast_cdr::start, ast_channel_snapshot_caller::subaddr, and cdr_object_snapshot::variables.

Referenced by cdr_object_swap_snapshot().

◆ cdr_object_update_party_b()

static int cdr_object_update_party_b ( void *  obj,
void *  arg,
void *  data,
int  flags 
)
static

Definition at line 2348 of file cdr.c.

2349{
2350 struct cdr_object *cdr = obj;
2351
2352 if (cdr->fn_table->process_party_b
2353 && !strcasecmp(cdr->party_b_name, arg)) {
2354 struct ast_channel_snapshot *party_b = data;
2355
2356 /*
2357 * For sanity's sake we also check the party_b snapshot
2358 * for consistency with the key. The callback needs and
2359 * asserts the snapshot to be this way.
2360 */
2361 if (!cdr->party_b.snapshot
2362 || strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name)) {
2364 "CDR for Party A %s(%s) has inconsistent Party B %s name. Message can be ignored but this shouldn't happen.\n",
2365 cdr->linkedid,
2366 cdr->party_a.snapshot->base->name,
2367 cdr->party_b_name);
2368 return 0;
2369 }
2370
2371 cdr->fn_table->process_party_b(cdr, party_b);
2372 }
2373 return 0;
2374}
void(*const process_party_b)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Process a Party B update for the cdr_object.
Definition cdr.c:550

References ast_log, ast_channel_snapshot::base, cdr_object::fn_table, cdr_object::linkedid, LOG_NOTICE, ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, cdr_object::party_b_name, cdr_object_fn_table::process_party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by handle_channel_snapshot_update_message().

◆ cdr_object_update_party_b_userfield_cb()

static int cdr_object_update_party_b_userfield_cb ( void *  obj,
void *  arg,
void *  data,
int  flags 
)
static

Callback used to update the userfield on Party B on all CDRs.

Definition at line 3608 of file cdr.c.

3609{
3610 struct cdr_object *cdr = obj;
3611
3612 if ((cdr->fn_table != &finalized_state_fn_table || !cdr->next)
3613 && !strcasecmp(cdr->party_b_name, arg)) {
3614 struct party_b_userfield_update *info = data;
3615
3616 /*
3617 * For sanity's sake we also assert the party_b snapshot
3618 * is consistent with the key.
3619 */
3621 && !strcasecmp(cdr->party_b.snapshot->base->name, info->channel_name));
3622
3623 ast_copy_string(cdr->party_b.userfield, info->userfield,
3624 sizeof(cdr->party_b.userfield));
3625 }
3626
3627 return 0;
3628}

References ast_assert, ast_copy_string(), ast_channel_snapshot::base, finalized_state_fn_table, cdr_object::fn_table, ast_channel_snapshot_base::name, cdr_object::next, cdr_object::party_b, cdr_object::party_b_name, cdr_object_snapshot::snapshot, cdr_object::start, and cdr_object_snapshot::userfield.

Referenced by ast_cdr_setuserfield().

◆ cdr_submit_batch()

static void cdr_submit_batch ( int  shutdown)
static

Definition at line 3919 of file cdr.c.

3920{
3921 struct module_config *mod_cfg;
3922 struct cdr_batch_item *oldbatchitems = NULL;
3923 pthread_t batch_post_thread = AST_PTHREADT_NULL;
3924
3925 /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
3926 if (!batch || !batch->head) {
3927 return;
3928 }
3929
3930 /* move the old CDRs aside, and prepare a new CDR batch */
3932 oldbatchitems = batch->head;
3933 reset_batch();
3935
3936 mod_cfg = ao2_global_obj_ref(module_configs);
3937
3938 /* if configured, spawn a new thread to post these CDRs,
3939 also try to save as much as possible if we are shutting down safely */
3940 if (!mod_cfg
3942 || do_shutdown) {
3943 ast_debug(1, "CDR single-threaded batch processing begins now\n");
3944 do_batch_backend_process(oldbatchitems);
3945 } else {
3946 if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
3947 ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
3948 do_batch_backend_process(oldbatchitems);
3949 } else {
3950 ast_debug(1, "CDR multi-threaded batch processing begins now\n");
3951 }
3952 }
3953
3954 ao2_cleanup(mod_cfg);
3955}
static void reset_batch(void)
Definition cdr.c:3883
static void * do_batch_backend_process(void *data)
Definition cdr.c:3902
@ BATCH_MODE_SCHEDULER_ONLY
Definition cdr.h:235
struct ast_flags settings
Definition cdr.h:274
struct ast_cdr_config::batch_settings batch_settings
#define ast_pthread_create_detached_background(a, b, c, d)
Definition utils.h:637

References ao2_cleanup, ao2_global_obj_ref, ast_debug, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_test_flag, batch, BATCH_MODE_SCHEDULER_ONLY, ast_cdr_config::batch_settings, cdr_batch_lock, do_batch_backend_process(), module_config::general, cdr_batch::head, LOG_WARNING, NULL, reset_batch(), and ast_cdr_config::batch_settings::settings.

Referenced by ast_cdr_engine_term(), and submit_scheduled_batch().

◆ cdr_toggle_runtime_options()

static int cdr_toggle_runtime_options ( void  )
static

Checks if CDRs are enabled and enables/disables the necessary options.

Definition at line 4645 of file cdr.c.

4646{
4647 struct module_config *mod_cfg;
4648
4649 mod_cfg = ao2_global_obj_ref(module_configs);
4650 if (mod_cfg
4651 && ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4652 if (create_subscriptions()) {
4654 ast_log(AST_LOG_ERROR, "Failed to create Stasis subscriptions\n");
4655 ao2_cleanup(mod_cfg);
4656 return -1;
4657 }
4658 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4660 } else {
4661 ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
4662 }
4663 } else {
4665 ast_log(LOG_NOTICE, "CDR logging disabled.\n");
4666 }
4667 ao2_cleanup(mod_cfg);
4668
4669 return mod_cfg ? 0 : -1;
4670}
static int create_subscriptions(void)
Create the Stasis subscriptions for CDRs.
Definition cdr.c:4471
static void cdr_enable_batch_mode(struct ast_cdr_config *config)
Definition cdr.c:4577
static void destroy_subscriptions(void)
Destroy the active Stasis subscriptions.
Definition cdr.c:4461
struct ast_flags settings
Definition cdr.h:270

References ao2_cleanup, ao2_global_obj_ref, ast_log, AST_LOG_ERROR, ast_test_flag, CDR_BATCHMODE, cdr_enable_batch_mode(), CDR_ENABLED, create_subscriptions(), destroy_subscriptions(), module_config::general, LOG_NOTICE, and ast_cdr_config::settings.

Referenced by ast_cdr_set_config(), load_module(), and reload_module().

◆ check_new_cdr_needed()

static int check_new_cdr_needed ( struct ast_channel_snapshot *  old_snapshot,
struct ast_channel_snapshot *  new_snapshot 
)
static

Determine if we need to add a new CDR based on snapshots.

Definition at line 2377 of file cdr.c.

2379{
2380 /* If we're dead, we don't need a new CDR */
2381 if (!new_snapshot
2384 return 0;
2385 }
2386
2387 /* Auto-fall through will increment the priority but have no application */
2388 if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
2389 return 0;
2390 }
2391
2392 if (old_snapshot && !snapshot_cep_changed(old_snapshot, new_snapshot)) {
2393 return 0;
2394 }
2395
2396 return 1;
2397}
static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Return whether or not a channel has changed its state in the dialplan, subject to endbeforehexten log...
Definition cdr.c:1250

References ast_channel_snapshot_dialplan::appl, AST_SOFTHANGUP_HANGUP_EXEC, ast_strlen_zero(), ast_test_flag, CDR_END_BEFORE_H_EXTEN, ast_channel_snapshot::dialplan, is_cdr_flag_set(), snapshot_cep_changed(), and ast_channel_snapshot::softhangup_flags.

Referenced by handle_channel_snapshot_update_message().

◆ cli_complete_show()

static char * cli_complete_show ( struct ast_cli_args *  a)
static

Complete user input for 'cdr show'.

Definition at line 4123 of file cdr.c.

4124{
4125 int wordlen = strlen(a->word);
4126 struct ao2_iterator it_cdrs;
4127 struct cdr_object *cdr;
4128
4130 while ((cdr = ao2_iterator_next(&it_cdrs))) {
4131 if (!strncasecmp(a->word, cdr->party_a.snapshot->base->name, wordlen)) {
4133 ao2_ref(cdr, -1);
4134 break;
4135 }
4136 }
4137 ao2_ref(cdr, -1);
4138 }
4140
4141 return NULL;
4142}
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition main/cli.c:2845
static struct test_val a

References a, active_cdrs_master, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_completion_add(), ast_strdup, ast_channel_snapshot::base, ast_channel_snapshot_base::name, NULL, cdr_object::party_a, cdr_object_snapshot::snapshot, and cdr_object::start.

Referenced by handle_cli_show().

◆ cli_show_channel()

static void cli_show_channel ( struct ast_cli_args *  a)
static

Definition at line 4208 of file cdr.c.

4209{
4210 struct cdr_object *it_cdr;
4211 char clid[64];
4212 char start_time_buffer[64];
4213 char answer_time_buffer[64];
4214 char end_time_buffer[64];
4215 const char *channel_name = a->argv[3];
4216 struct cdr_object *cdr;
4217
4218#define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4219#define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4220
4221 cdr = cdr_object_get_by_name(channel_name);
4222 if (!cdr) {
4223 ast_cli(a->fd, "Unknown channel: %s\n", channel_name);
4224 return;
4225 }
4226
4227 ast_cli(a->fd, "\n");
4228 ast_cli(a->fd, "Call Detail Record (CDR) Information for %s\n", channel_name);
4229 ast_cli(a->fd, "--------------------------------------------------\n");
4230 ast_cli(a->fd, TITLE_STRING, "AccountCode", "CallerID", "Dst. Channel", "LastApp", "Data", "Start", "Answer", "End", "Billsec", "Duration");
4231
4232 ao2_lock(cdr);
4233 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4234 struct timeval end;
4235
4236 if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4237 continue;
4238 }
4239 ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller->name, it_cdr->party_a.snapshot->caller->number, "");
4240 if (ast_tvzero(it_cdr->end)) {
4241 end = ast_tvnow();
4242 } else {
4243 end = it_cdr->end;
4244 }
4245 cdr_get_tv(it_cdr->start, "%T", start_time_buffer, sizeof(start_time_buffer));
4246 cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4247 cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
4248 ast_cli(a->fd, FORMAT_STRING,
4249 it_cdr->party_a.snapshot->base->accountcode,
4250 clid,
4251 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4252 it_cdr->appl,
4253 it_cdr->data,
4254 start_time_buffer,
4255 answer_time_buffer,
4256 end_time_buffer,
4257 (long)ast_tvdiff_ms(end, it_cdr->answer) / 1000,
4258 (long)ast_tvdiff_ms(end, it_cdr->start) / 1000);
4259 }
4260 ao2_unlock(cdr);
4261
4262 ao2_cleanup(cdr);
4263
4264#undef FORMAT_STRING
4265#undef TITLE_STRING
4266}
#define FORMAT_STRING
#define TITLE_STRING
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6

References a, ast_channel_snapshot_base::accountcode, cdr_object::answer, ao2_cleanup, ao2_lock, ao2_unlock, cdr_object::appl, ast_callerid_merge(), ast_cli(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_channel_snapshot::base, ast_channel_snapshot::caller, cdr_get_tv(), cdr_object_get_by_name(), cdr_object::data, end, cdr_object::end, FORMAT_STRING, ast_channel_snapshot_caller::name, ast_channel_snapshot_base::name, cdr_object::next, ast_channel_snapshot_caller::number, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, snapshot_is_dialed(), cdr_object::start, and TITLE_STRING.

Referenced by handle_cli_show().

◆ cli_show_channels()

static void cli_show_channels ( struct ast_cli_args *  a)
static

Definition at line 4144 of file cdr.c.

4145{
4146 struct ao2_iterator it_cdrs;
4147 struct cdr_object *cdr;
4148 char start_time_buffer[64];
4149 char answer_time_buffer[64];
4150 char end_time_buffer[64];
4151
4152#define TITLE_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4153#define FORMAT_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4154
4155 ast_cli(a->fd, "\n");
4156 ast_cli(a->fd, "Channels with Call Detail Record (CDR) Information\n");
4157 ast_cli(a->fd, "--------------------------------------------------\n");
4158 ast_cli(a->fd, TITLE_STRING, "Channel", "Dst. Channel", "LastApp", "Start", "Answer", "End", "Billsec", "Duration");
4159
4161 for (; (cdr = ao2_iterator_next(&it_cdrs)); ao2_cleanup(cdr)) {
4162 struct cdr_object *it_cdr;
4163 struct timeval start_time = { 0, };
4164 struct timeval answer_time = { 0, };
4165 struct timeval end_time = { 0, };
4166
4167 SCOPED_AO2LOCK(lock, cdr);
4168
4169 /* Calculate the start, end, answer, billsec, and duration over the
4170 * life of all of the CDR entries
4171 */
4172 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4173 if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4174 continue;
4175 }
4176 if (ast_tvzero(start_time)) {
4177 start_time = it_cdr->start;
4178 }
4179 if (!ast_tvzero(it_cdr->answer) && ast_tvzero(answer_time)) {
4180 answer_time = it_cdr->answer;
4181 }
4182 }
4183
4184 /* If there was no start time, then all CDRs were for a dialed channel; skip */
4185 if (ast_tvzero(start_time)) {
4186 continue;
4187 }
4188 it_cdr = cdr->last;
4189
4190 end_time = ast_tvzero(it_cdr->end) ? ast_tvnow() : it_cdr->end;
4191 cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
4192 cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4193 cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
4195 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4196 it_cdr->appl,
4197 start_time_buffer,
4198 answer_time_buffer,
4199 end_time_buffer,
4200 ast_tvzero(answer_time) ? 0 : (long)ast_tvdiff_ms(end_time, answer_time) / 1000,
4201 (long)ast_tvdiff_ms(end_time, start_time) / 1000);
4202 }
4203 ao2_iterator_destroy(&it_cdrs);
4204#undef FORMAT_STRING
4205#undef TITLE_STRING
4206}

References a, active_cdrs_master, cdr_object::answer, ao2_cleanup, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, cdr_object::appl, ast_cli(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_channel_snapshot::base, cdr_get_tv(), cdr_object::end, FORMAT_STRING, cdr_object::last, lock, ast_channel_snapshot_base::name, cdr_object::next, cdr_object::party_a, cdr_object::party_b, SCOPED_AO2LOCK, cdr_object_snapshot::snapshot, snapshot_is_dialed(), cdr_object::start, and TITLE_STRING.

Referenced by handle_cli_show().

◆ CONFIG_INFO_CORE()

CONFIG_INFO_CORE ( "cdr"  ,
cfg_info  ,
module_configs  ,
module_config_alloc  ,
.  files = ACO_FILES(&module_file_conf),
.  post_apply_config = module_config_post_apply 
)

◆ copy_variables()

static int copy_variables ( struct varshead *  to_list,
struct varshead *  from_list 
)
static

Copy variables from one list to another.

Parameters
to_listdestination
from_listsource
Returns
The number of copied variables

Definition at line 851 of file cdr.c.

852{
853 struct ast_var_t *variables;
854 struct ast_var_t *newvariable;
855 const char *var;
856 const char *val;
857 int x = 0;
858
859 AST_LIST_TRAVERSE(from_list, variables, entries) {
860 var = ast_var_name(variables);
861 if (ast_strlen_zero(var)) {
862 continue;
863 }
864 val = ast_var_value(variables);
865 if (ast_strlen_zero(val)) {
866 continue;
867 }
868 newvariable = ast_var_assign(var, val);
869 if (newvariable) {
870 AST_LIST_INSERT_HEAD(to_list, newvariable, entries);
871 ++x;
872 }
873 }
874
875 return x;
876}
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.

References AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_assign, ast_var_name(), ast_var_value(), ast_var_t::entries, and var.

Referenced by ast_cdr_dup(), ast_cdr_fork(), cdr_object_create_public_records(), and cdr_object_snapshot_copy().

◆ create_subscriptions()

static int create_subscriptions ( void  )
static

Create the Stasis subscriptions for CDRs.

Definition at line 4471 of file cdr.c.

4472{
4473 if (!cdr_topic) {
4474 return -1;
4475 }
4476
4478 return 0;
4479 }
4480
4482 if (!channel_subscription) {
4483 return -1;
4484 }
4486 if (!bridge_subscription) {
4487 return -1;
4488 }
4490 if (!parking_subscription) {
4491 return -1;
4492 }
4493
4494 return 0;
4495}
static struct stasis_forward * bridge_subscription
Our subscription for bridges.
Definition cdr.c:478
static struct stasis_forward * channel_subscription
Our subscription for channels.
Definition cdr.c:481
static struct stasis_forward * parking_subscription
Our subscription for parking.
Definition cdr.c:484
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_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:1656
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.

References ast_bridge_topic_all(), ast_channel_topic_all(), ast_parking_topic(), bridge_subscription, cdr_topic, channel_subscription, parking_subscription, and stasis_forward_all().

Referenced by cdr_toggle_runtime_options().

◆ destroy_subscriptions()

static void destroy_subscriptions ( void  )
static

◆ dial_state_process_bridge_enter()

static enum process_bridge_enter_results dial_state_process_bridge_enter ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel 
)
static

Definition at line 1990 of file cdr.c.

1991{
1992 int success = 0;
1993
1994 ast_string_field_set(cdr, bridge, bridge->uniqueid);
1995
1996 /* Get parties in the bridge */
1997 if (ao2_container_count(bridge->channels) == 1) {
1998 /* No one in the bridge yet but us! */
2001 }
2002
2003 /* If we don't have a Party B (originated channel), skip it */
2004 if (cdr->party_b.snapshot) {
2005 struct ao2_iterator it_cdrs;
2006 char *channel_id;
2007
2008 for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
2009 !success && (channel_id = ao2_iterator_next(&it_cdrs));
2010 ao2_ref(channel_id, -1)) {
2012 struct cdr_object *cand_cdr;
2013
2015 if (!cand_cdr_master) {
2016 continue;
2017 }
2018
2021 /* Skip any records that are not in a bridge or in this bridge.
2022 * I'm not sure how that would happen, but it pays to be careful. */
2023 if (cand_cdr->fn_table != &bridge_state_fn_table
2024 || strcmp(cdr->bridge, cand_cdr->bridge)) {
2025 continue;
2026 }
2027
2028 /* Skip any records that aren't our Party B */
2029 if (strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
2030 continue;
2031 }
2032 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
2033 /* If they have a Party B, they joined up with someone else as their
2034 * Party A. Don't finalize them as they're active. Otherwise, we
2035 * have stolen them so they need to be finalized.
2036 */
2037 if (!cand_cdr->party_b.snapshot) {
2039 }
2040 success = 1;
2041 break;
2042 }
2045 }
2047 }
2048
2049 /* We always transition state, even if we didn't get a peer */
2051
2052 /* Success implies that we have a Party B */
2053 if (success) {
2055 }
2057}
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
struct ao2_container * channels
Definition bridge.h:335

References active_cdrs_master, ao2_cleanup, ao2_container_count(), ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_string_field_set, ast_channel_snapshot::base, ast_channel_snapshot::bridge, cdr_object::bridge, BRIDGE_ENTER_NO_PARTY_B, BRIDGE_ENTER_OBTAINED_PARTY_B, BRIDGE_ENTER_ONLY_PARTY, bridge_state_fn_table, cdr_object_finalize(), cdr_object_snapshot_copy(), cdr_object_transition_state(), ast_bridge_snapshot::channels, ast_channel_snapshot_base::name, OBJ_SEARCH_KEY, cdr_object::party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

◆ dial_state_process_dial_begin()

static int dial_state_process_dial_begin ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  caller,
struct ast_channel_snapshot *  peer 
)
static

Definition at line 1920 of file cdr.c.

1921{
1922 /* Don't process a begin dial here. A party A already in the dial state will
1923 * who receives a dial begin for something else will be handled by the
1924 * message router callback and will add a new CDR for the party A */
1925 return 1;
1926}

◆ dial_state_process_dial_end()

static int dial_state_process_dial_end ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  caller,
struct ast_channel_snapshot *  peer,
const char *  dial_status 
)
static

Definition at line 1958 of file cdr.c.

1959{
1960 struct ast_channel_snapshot *party_a;
1961
1962 if (caller) {
1963 party_a = caller;
1964 } else {
1965 party_a = peer;
1966 }
1967 ast_assert(!strcasecmp(cdr->party_a.snapshot->base->name, party_a->base->name));
1968 cdr_object_swap_snapshot(&cdr->party_a, party_a);
1969
1970 if (cdr->party_b.snapshot) {
1971 if (strcasecmp(cdr->party_b.snapshot->base->name, peer->base->name)) {
1972 /* Not the status for this CDR - defer back to the message router */
1973 return 1;
1974 }
1976 }
1977
1978 /* Set the disposition based on the dial string. */
1979 cdr->disposition = dial_status_to_disposition(dial_status);
1980 if (cdr->disposition == AST_CDR_ANSWERED) {
1981 /* Switch to dial pending to wait and see what the caller does */
1983 } else {
1985 }
1986
1987 return 0;
1988}
static enum ast_cdr_disposition dial_status_to_disposition(const char *dial_status)
Definition cdr.c:1932
struct cdr_object_fn_table dialed_pending_state_fn_table
The virtual table for the Dialed Pending state.
Definition cdr.c:741

References ast_assert, AST_CDR_ANSWERED, ast_channel_snapshot::base, ast_channel_snapshot::caller, cdr_object_swap_snapshot(), cdr_object_transition_state(), dial_status_to_disposition(), dialed_pending_state_fn_table, cdr_object::disposition, finalized_state_fn_table, ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, ast_channel_snapshot::peer, and cdr_object_snapshot::snapshot.

◆ dial_state_process_party_b()

static void dial_state_process_party_b ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  snapshot 
)
static

◆ dial_status_end()

static int dial_status_end ( const char *  dialstatus)
static

Definition at line 2199 of file cdr.c.

2200{
2201 return (strcmp(dialstatus, "RINGING") &&
2202 strcmp(dialstatus, "PROCEEDING") &&
2203 strcmp(dialstatus, "PROGRESS"));
2204}

References cdr_object::start.

Referenced by handle_dial_message().

◆ dial_status_to_disposition()

static enum ast_cdr_disposition dial_status_to_disposition ( const char *  dial_status)
static

Definition at line 1932 of file cdr.c.

1933{
1934 if (!strcmp(dial_status, "ANSWER")) {
1935 return AST_CDR_ANSWERED;
1936 } else if (!strcmp(dial_status, "BUSY")) {
1937 return AST_CDR_BUSY;
1938 } else if (!strcmp(dial_status, "CANCEL")) {
1940 return AST_CDR_NOANSWER;
1941 } else {
1942 return AST_CDR_CANCEL;
1943 }
1944 } else if (!strcmp(dial_status, "NOANSWER")) {
1945 return AST_CDR_NOANSWER;
1946 } else if (!strcmp(dial_status, "CONGESTION")) {
1948 return AST_CDR_FAILED;
1949 } else {
1950 return AST_CDR_CONGESTION;
1951 }
1952 } else if (!strcmp(dial_status, "FAILED")) {
1953 return AST_CDR_FAILED;
1954 }
1955 return AST_CDR_FAILED;
1956}
@ CDR_CANCEL_DISPOSITION_ENABLED
Definition cdr.h:230

References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_CANCEL, AST_CDR_CONGESTION, AST_CDR_FAILED, AST_CDR_NOANSWER, CDR_CANCEL_DISPOSITION_ENABLED, CDR_CONGESTION, is_cdr_flag_set(), and cdr_object::start.

Referenced by dial_state_process_dial_end(), and handle_dial_message().

◆ dialed_pending_state_process_bridge_enter()

static enum process_bridge_enter_results dialed_pending_state_process_bridge_enter ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel 
)
static

Definition at line 2086 of file cdr.c.

2087{
2089 return cdr->fn_table->process_bridge_enter(cdr, bridge, channel);
2090}
struct cdr_object_fn_table dial_state_fn_table
The virtual table for the Dial state.
Definition cdr.c:708
enum process_bridge_enter_results(*const process_bridge_enter)(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Process the entering of a bridge by this CDR. The purpose of this callback is to have the CDR prepare...
Definition cdr.c:607

References cdr_object::bridge, cdr_object_transition_state(), dial_state_fn_table, cdr_object::fn_table, and cdr_object_fn_table::process_bridge_enter.

◆ dialed_pending_state_process_dial_begin()

static int dialed_pending_state_process_dial_begin ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  caller,
struct ast_channel_snapshot *  peer 
)
static

Definition at line 2102 of file cdr.c.

2103{
2105
2106 /* Ask for a new CDR */
2107 return 1;
2108}

References cdr_object_transition_state(), and finalized_state_fn_table.

◆ dialed_pending_state_process_parking_bridge_enter()

static int dialed_pending_state_process_parking_bridge_enter ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel 
)
static

Definition at line 2092 of file cdr.c.

2093{
2094 if (cdr->party_b.snapshot) {
2095 /* We can't handle this as we have a Party B - ask for a new one */
2096 return 1;
2097 }
2099 return 0;
2100}
struct cdr_object_fn_table parked_state_fn_table
The virtual table for the Parked state.
Definition cdr.c:782

References cdr_object_transition_state(), parked_state_fn_table, cdr_object::party_b, and cdr_object_snapshot::snapshot.

◆ dialed_pending_state_process_party_a()

static int dialed_pending_state_process_party_a ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  snapshot 
)
static

Definition at line 2061 of file cdr.c.

2062{
2063 /* If we get a CEP change, we're executing dialplan. If we have a Party B
2064 * that means we need a new CDR; otherwise, switch us over to single.
2065 */
2066 if (snapshot_cep_changed(cdr->party_a.snapshot, snapshot)) {
2067 if (cdr->party_b.snapshot) {
2069 cdr->fn_table->process_party_a(cdr, snapshot);
2070 return 1;
2071 } else {
2072 /* The CDR does not need to be reinitialized when transitioning
2073 * to its single state as this would overwrite the start time,
2074 * causing potentially both the answer and the start time to be
2075 * the same which is incorrect.
2076 */
2078 cdr->fn_table->process_party_a(cdr, snapshot);
2079 return 0;
2080 }
2081 }
2082 base_process_party_a(cdr, snapshot);
2083 return 0;
2084}
static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition cdr.c:1644

References base_process_party_a(), cdr_object_transition_state(), cdr_object_transition_state_init(), finalized_state_fn_table, cdr_object::fn_table, cdr_object::party_a, cdr_object::party_b, cdr_object_fn_table::process_party_a, single_state_fn_table, cdr_object_snapshot::snapshot, and snapshot_cep_changed().

◆ do_batch_backend_process()

static void * do_batch_backend_process ( void *  data)
static

Definition at line 3902 of file cdr.c.

3903{
3904 struct cdr_batch_item *processeditem;
3905 struct cdr_batch_item *batchitem = data;
3906
3907 /* Push each CDR into storage mechanism(s) and free all the memory */
3908 while (batchitem) {
3909 post_cdr(batchitem->cdr);
3910 ast_cdr_free(batchitem->cdr);
3911 processeditem = batchitem;
3912 batchitem = batchitem->next;
3913 ast_free(processeditem);
3914 }
3915
3916 return NULL;
3917}

References ast_cdr_free(), ast_free, cdr_batch_item::cdr, cdr_batch_item::next, NULL, and post_cdr().

Referenced by cdr_submit_batch().

◆ do_cdr()

static void * do_cdr ( void *  data)
static

Definition at line 4056 of file cdr.c.

4057{
4058 struct timespec timeout;
4059 int schedms;
4060 int numevents = 0;
4061
4062 for (;;) {
4063 struct timeval now;
4064 schedms = ast_sched_wait(sched);
4065 /* this shouldn't happen, but provide a 1 second default just in case */
4066 if (schedms < 0)
4067 schedms = 1000;
4068 now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
4069 timeout.tv_sec = now.tv_sec;
4070 timeout.tv_nsec = now.tv_usec * 1000;
4071 /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
4074 numevents = ast_sched_runq(sched);
4076 ast_debug(2, "Processed %d CDR batches from the run queue\n", numevents);
4077 }
4078
4079 return NULL;
4080}
static ast_mutex_t cdr_pending_lock
These are used to wake up the CDR thread when there's work to do.
Definition cdr.c:465
#define ast_cond_timedwait(cond, mutex, time)
Definition lock.h:213
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition sched.c:786
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition sched.c:433
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition time.h:282
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition extconf.c:2278

References ast_cond_timedwait, ast_debug, ast_mutex_lock, ast_mutex_unlock, ast_samp2tv(), ast_sched_runq(), ast_sched_wait(), ast_tvadd(), ast_tvnow(), cdr_pending_cond, cdr_pending_lock, and NULL.

Referenced by cdr_enable_batch_mode().

◆ filter_bridge_messages()

static int filter_bridge_messages ( struct ast_bridge_snapshot *  bridge)
static

Filter bridge messages based on bridge technology.

Definition at line 2526 of file cdr.c.

2527{
2528 /* Ignore holding bridge technology messages. We treat this simply as an application
2529 * that a channel enters into.
2530 */
2531 if (!strcmp(bridge->technology, "holding_bridge") && strcmp(bridge->subclass, "parking")) {
2532 return 1;
2533 }
2534 return 0;
2535}
const ast_string_field technology
Definition bridge.h:332
const ast_string_field subclass
Definition bridge.h:332

References bridge_leave_data::bridge, ast_bridge_snapshot::subclass, and ast_bridge_snapshot::technology.

Referenced by handle_bridge_enter_message(), and handle_bridge_leave_message().

◆ filter_channel_snapshot()

static int filter_channel_snapshot ( struct ast_channel_snapshot *  snapshot)
static

Definition at line 2174 of file cdr.c.

2175{
2176 return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
2177}
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition channel.h:991

References AST_CHAN_TP_INTERNAL, ast_channel_snapshot::base, and ast_channel_snapshot_base::tech_properties.

Referenced by filter_channel_snapshot_message(), handle_bridge_enter_message(), handle_bridge_leave_message(), handle_dial_message(), and handle_parked_call_message().

◆ filter_channel_snapshot_message()

static int filter_channel_snapshot_message ( struct ast_channel_snapshot *  old_snapshot,
struct ast_channel_snapshot *  new_snapshot 
)
static

Definition at line 2183 of file cdr.c.

2185{
2186 int ret = 0;
2187
2188 /* Drop cache updates from certain channel technologies */
2189 if (old_snapshot) {
2190 ret |= filter_channel_snapshot(old_snapshot);
2191 }
2192 if (new_snapshot) {
2193 ret |= filter_channel_snapshot(new_snapshot);
2194 }
2195
2196 return ret;
2197}
static int filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
Definition cdr.c:2174

References filter_channel_snapshot().

Referenced by handle_channel_snapshot_update_message().

◆ finalize_batch_mode()

static void finalize_batch_mode ( void  )
static

Definition at line 4434 of file cdr.c.

4435{
4437 return;
4438 }
4439 /* wake up the thread so it will exit */
4440 pthread_cancel(cdr_thread);
4441 pthread_kill(cdr_thread, SIGURG);
4442 pthread_join(cdr_thread, NULL);
4446}
void ast_cdr_engine_term(void)
Definition cdr.c:4758
#define ast_cond_destroy(cond)
Definition lock.h:209

References ast_cdr_engine_term(), ast_cond_destroy, AST_PTHREADT_NULL, cdr_pending_cond, cdr_thread, NULL, and cdr_object::start.

Referenced by cdr_engine_shutdown(), and reload_module().

◆ finalized_state_init_function()

static void finalized_state_init_function ( struct cdr_object *  cdr)
static

Definition at line 2154 of file cdr.c.

2155{
2157}

References cdr_object_finalize().

◆ finalized_state_process_party_a()

static int finalized_state_process_party_a ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  snapshot 
)
static

Definition at line 2159 of file cdr.c.

2160{
2163 return 0;
2164 }
2165
2166 /* Indicate that, if possible, we should get a new CDR */
2167 return 1;
2168}

References AST_SOFTHANGUP_HANGUP_EXEC, ast_test_flag, CDR_END_BEFORE_H_EXTEN, is_cdr_flag_set(), and ast_channel_snapshot::softhangup_flags.

◆ free_variables()

static void free_variables ( struct varshead *  headp)
static

Delete all variables from a variable list.

Parameters
headpThe head pointer to the variable list to delete

Definition at line 882 of file cdr.c.

883{
884 struct ast_var_t *vardata;
885
886 while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
887 ast_var_delete(vardata);
888 }
889}

References AST_LIST_REMOVE_HEAD, ast_var_delete(), and ast_var_t::entries.

Referenced by ast_cdr_fork(), and ast_cdr_free().

◆ handle_bridge_enter_message()

static void handle_bridge_enter_message ( void *  data,
struct stasis_subscription *  sub,
struct stasis_message *  message 
)
static

Definition at line 2848 of file cdr.c.

2850{
2852 struct ast_bridge_snapshot *bridge = update->bridge;
2853 struct ast_channel_snapshot *channel = update->channel;
2854 struct cdr_object *cdr;
2855
2857 return;
2858 }
2859
2860 if (filter_channel_snapshot(channel)) {
2861 return;
2862 }
2863
2864 CDR_DEBUG("Bridge Enter message for channel %s: %u.%08u\n",
2865 channel->base->name,
2866 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2867 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2868
2870 if (!cdr) {
2871 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2872 ast_assert(0);
2873 return;
2874 }
2875
2876 if (!strcmp(bridge->subclass, "parking")) {
2878 } else {
2880 }
2881 ao2_cleanup(cdr);
2882}
static void handle_standard_bridge_enter_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel, const struct timeval *event_time)
Handle a bridge enter message for a 'normal' bridge.
Definition cdr.c:2768
static int filter_bridge_messages(struct ast_bridge_snapshot *bridge)
Filter bridge messages based on bridge technology.
Definition cdr.c:2526
static void handle_parking_bridge_enter_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel, const struct timeval *event_time)
Handle entering into a parking bridge.
Definition cdr.c:2726
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
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
Blob of data associated with a bridge.
Structure that contains a snapshot of information about a bridge.
Definition bridge.h:318

References active_cdrs_master, ao2_cleanup, ao2_find, ast_assert, ast_log, AST_LOG_WARNING, ast_channel_snapshot::base, cdr_object::bridge, CDR_DEBUG, filter_bridge_messages(), filter_channel_snapshot(), handle_parking_bridge_enter_message(), handle_standard_bridge_enter_message(), ast_channel_snapshot_base::name, OBJ_SEARCH_KEY, cdr_object::start, stasis_message_data(), stasis_message_timestamp(), ast_channel_snapshot_base::uniqueid, and update().

Referenced by load_module().

◆ handle_bridge_leave_message()

static void handle_bridge_leave_message ( void *  data,
struct stasis_subscription *  sub,
struct stasis_message *  message 
)
static

Handler for when a channel leaves a bridge.

Parameters
dataPassed on
subThe stasis subscription for this message callback
messageThe message - hopefully a bridge one!

Definition at line 2543 of file cdr.c.

2545{
2547 struct ast_bridge_snapshot *bridge = update->bridge;
2548 struct ast_channel_snapshot *channel = update->channel;
2549 struct cdr_object *cdr;
2550 struct cdr_object *it_cdr;
2551 struct bridge_leave_data leave_data = {
2552 .bridge = bridge,
2553 .channel = channel,
2554 .lastevent = stasis_message_timestamp(message)
2555 };
2556 int left_bridge = 0;
2557
2559 return;
2560 }
2561
2563 return;
2564 }
2565
2566 CDR_DEBUG("Bridge Leave message for %s: %u.%08u\n",
2567 channel->base->name,
2568 (unsigned int)leave_data.lastevent->tv_sec,
2569 (unsigned int)leave_data.lastevent->tv_usec);
2570
2572 if (!cdr) {
2573 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2574 ast_assert(0);
2575 return;
2576 }
2577
2578 /* Party A */
2579 ao2_lock(cdr);
2580 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2581 it_cdr->lastevent = *leave_data.lastevent;
2582 if (!it_cdr->fn_table->process_bridge_leave) {
2583 continue;
2584 }
2585 CDR_DEBUG("%p - Processing Bridge Leave for %s\n",
2586 it_cdr, channel->base->name);
2587 if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
2588 ast_string_field_set(it_cdr, bridge, "");
2589 left_bridge = 1;
2590 }
2591 }
2592 ao2_unlock(cdr);
2593
2594 /* Party B */
2595 if (left_bridge
2596 && strcmp(bridge->subclass, "parking")) {
2598 cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->base->name,
2599 &leave_data);
2600 }
2601
2602 ao2_cleanup(cdr);
2603}
static int cdr_object_party_b_left_bridge_cb(void *obj, void *arg, void *data, int flags)
Callback used to notify CDRs of a Party B leaving the bridge.
Definition cdr.c:2501
int(*const process_bridge_leave)(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Process the leaving of a bridge by this CDR.
Definition cdr.c:637

References active_cdrs_all, active_cdrs_master, ao2_callback_data, ao2_cleanup, ao2_find, ao2_lock, ao2_unlock, ast_assert, ast_log, AST_LOG_WARNING, ast_string_field_set, ast_channel_snapshot::base, bridge_leave_data::bridge, CDR_DEBUG, cdr_object_party_b_left_bridge_cb(), bridge_leave_data::channel, filter_bridge_messages(), filter_channel_snapshot(), cdr_object::fn_table, cdr_object::lastevent, bridge_leave_data::lastevent, ast_channel_snapshot_base::name, cdr_object::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_SEARCH_KEY, cdr_object_fn_table::process_bridge_leave, cdr_object::start, stasis_message_data(), stasis_message_timestamp(), ast_bridge_snapshot::subclass, ast_channel_snapshot_base::uniqueid, and update().

Referenced by load_module().

◆ handle_bridge_pairings()

static void handle_bridge_pairings ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge 
)
static

Handle creating bridge pairings for the cdr_object that just entered a bridge.

Parameters
cdrThe cdr_object that just entered the bridge
bridgeThe ast_bridge_snapshot representing the bridge it just entered

Definition at line 2700 of file cdr.c.

2701{
2702 struct ao2_iterator it_channels;
2703 char *channel_id;
2704
2705 it_channels = ao2_iterator_init(bridge->channels, 0);
2706 while ((channel_id = ao2_iterator_next(&it_channels))) {
2707 struct cdr_object *cand_cdr;
2708
2710 if (cand_cdr) {
2712 ao2_ref(cand_cdr, -1);
2713 }
2714
2715 ao2_ref(channel_id, -1);
2716 }
2718}
static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr)
Process a single bridge_candidate.
Definition cdr.c:2642

References active_cdrs_master, ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, bridge_candidate_process(), ast_bridge_snapshot::channels, OBJ_SEARCH_KEY, and cdr_object::start.

Referenced by handle_standard_bridge_enter_message().

◆ handle_cdr_sync_message()

static void handle_cdr_sync_message ( void *  data,
struct stasis_subscription *  sub,
struct stasis_message *  message 
)
static

Handler for a synchronization message.

Parameters
dataPassed on
subThe stasis subscription for this message callback
messageA blank ao2 object

Definition at line 2958 of file cdr.c.

2960{
2961 return;
2962}

Referenced by load_module().

◆ handle_channel_snapshot_update_message()

static void handle_channel_snapshot_update_message ( void *  data,
struct stasis_subscription *  sub,
struct stasis_message *  message 
)
static

Handler for channel snapshot update messages.

Parameters
dataPassed on
subThe stasis subscription for this message callback
messageThe message

Definition at line 2405 of file cdr.c.

2406{
2407 struct cdr_object *cdr;
2409 struct cdr_object *it_cdr;
2410
2411 if (filter_channel_snapshot_message(update->old_snapshot, update->new_snapshot)) {
2412 return;
2413 }
2414
2415 if (update->new_snapshot && !update->old_snapshot) {
2416 struct module_config *mod_cfg = NULL;
2417
2419 if (!cdr) {
2420 return;
2421 }
2422 mod_cfg = ao2_global_obj_ref(module_configs);
2423 cdr->is_root = 1;
2425
2426 /* If CDR should be disabled unless enabled on a per-channel basis, then disable
2427 CDR, right from the get go */
2428 if (mod_cfg) {
2430 ast_debug(3, "Disable CDR by default\n");
2432 }
2433 ao2_cleanup(mod_cfg);
2434 }
2435 } else {
2436 cdr = ao2_find(active_cdrs_master, update->new_snapshot->base->uniqueid, OBJ_SEARCH_KEY);
2437 }
2438
2439 /* Handle Party A */
2440 if (!cdr) {
2441 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->base->name);
2442 ast_assert(0);
2443 } else {
2444 int all_reject = 1;
2445
2446 ao2_lock(cdr);
2447 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2449 if (!it_cdr->fn_table->process_party_a) {
2450 continue;
2451 }
2452 all_reject &= it_cdr->fn_table->process_party_a(it_cdr, update->new_snapshot);
2453 }
2454 if (all_reject && check_new_cdr_needed(update->old_snapshot, update->new_snapshot)) {
2455 /* We're not hung up and we have a new snapshot - we need a new CDR */
2456 struct cdr_object *new_cdr;
2457
2459 if (new_cdr) {
2460 new_cdr->fn_table->process_party_a(new_cdr, update->new_snapshot);
2461 }
2462 }
2463 ao2_unlock(cdr);
2464 }
2465
2466 if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
2467 ao2_lock(cdr);
2468 CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->base->name);
2469 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2472 }
2474 ao2_unlock(cdr);
2475
2476 cdr_all_unlink(cdr);
2478 }
2479
2480 /* Handle Party B */
2481 if (update->new_snapshot) {
2483 cdr_object_update_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
2484 }
2485
2486 if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
2488 cdr_object_finalize_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
2489 }
2490
2491 ao2_cleanup(cdr);
2492}
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition astobj2.h:1578
static int cdr_object_update_party_b(void *obj, void *arg, void *data, int flags)
Definition cdr.c:2348
static int cdr_object_finalize_party_b(void *obj, void *arg, void *data, int flags)
Definition cdr.c:2324
static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Determine if we need to add a new CDR based on snapshots.
Definition cdr.c:2377
static int filter_channel_snapshot_message(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Definition cdr.c:2183
@ CDR_CHANNEL_DEFAULT_ENABLED
Definition cdr.h:227
Structure representing a change of snapshot of channel state.

References active_cdrs_all, active_cdrs_master, ao2_callback_data, ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_link, ao2_lock, ao2_unlink, ao2_unlock, ast_assert, AST_CDR_FLAG_DISABLE_ALL, ast_debug, AST_FLAG_DEAD, ast_log, AST_LOG_WARNING, ast_set_flag, ast_test_flag, cdr_all_unlink(), CDR_CHANNEL_DEFAULT_ENABLED, CDR_DEBUG, cdr_object_alloc(), cdr_object_create_and_append(), cdr_object_dispatch(), cdr_object_finalize(), cdr_object_finalize_party_b(), cdr_object_update_party_b(), check_new_cdr_needed(), filter_channel_snapshot_message(), cdr_object::flags, cdr_object::fn_table, module_config::general, cdr_object::is_root, cdr_object::lastevent, cdr_object::name, cdr_object::next, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_SEARCH_KEY, cdr_object_fn_table::process_party_a, ast_cdr_config::settings, cdr_object::start, stasis_message_data(), stasis_message_timestamp(), and update().

Referenced by load_module().

◆ handle_cli_debug()

static char * handle_cli_debug ( struct ast_cli_entry *  e,
int  cmd,
struct ast_cli_args *  a 
)
static

Definition at line 4082 of file cdr.c.

4083{
4084 struct module_config *mod_cfg;
4085
4086 switch (cmd) {
4087 case CLI_INIT:
4088 e->command = "cdr set debug [on|off]";
4089 e->usage = "Enable or disable extra debugging in the CDR Engine. Note\n"
4090 "that this will dump debug information to the VERBOSE setting\n"
4091 "and should only be used when debugging information from the\n"
4092 "CDR engine is needed.\n";
4093 return NULL;
4094 case CLI_GENERATE:
4095 return NULL;
4096 }
4097
4098 if (a->argc != 4) {
4099 return CLI_SHOWUSAGE;
4100 }
4101
4102 mod_cfg = ao2_global_obj_ref(module_configs);
4103 if (!mod_cfg) {
4104 ast_cli(a->fd, "Could not set CDR debugging mode\n");
4105 return CLI_SUCCESS;
4106 }
4107 if (!strcasecmp(a->argv[3], "on")
4108 && !ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
4110 ast_cli(a->fd, "CDR debugging enabled\n");
4111 } else if (!strcasecmp(a->argv[3], "off")
4112 && ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
4114 ast_cli(a->fd, "CDR debugging disabled\n");
4115 }
4116 cdr_set_debug_mode(mod_cfg);
4117 ao2_cleanup(mod_cfg);
4118
4119 return CLI_SUCCESS;
4120}
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177

References a, ao2_cleanup, ao2_global_obj_ref, ast_clear_flag, ast_cli(), ast_set_flag, ast_test_flag, CDR_DEBUG, cdr_set_debug_mode, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, module_config::general, NULL, ast_cdr_config::settings, and ast_cli_entry::usage.

◆ handle_cli_show()

static char * handle_cli_show ( struct ast_cli_entry *  e,
int  cmd,
struct ast_cli_args *  a 
)
static

Definition at line 4268 of file cdr.c.

4269{
4270 switch (cmd) {
4271 case CLI_INIT:
4272 e->command = "cdr show active";
4273 e->usage =
4274 "Usage: cdr show active [channel]\n"
4275 " Displays a summary of all Call Detail Records when [channel]\n"
4276 " is omitted; displays all of the Call Detail Records\n"
4277 " currently in flight for a given [channel] when [channel] is\n"
4278 " specified.\n\n"
4279 " Note that this will not display Call Detail Records that\n"
4280 " have already been dispatched to a backend storage, nor for\n"
4281 " channels that are no longer active.\n";
4282 return NULL;
4283 case CLI_GENERATE:
4284 return cli_complete_show(a);
4285 }
4286
4287 if (a->argc > 4) {
4288 return CLI_SHOWUSAGE;
4289 } else if (a->argc < 4) {
4291 } else {
4293 }
4294
4295 return CLI_SUCCESS;
4296}
static void cli_show_channels(struct ast_cli_args *a)
Definition cdr.c:4144
static char * cli_complete_show(struct ast_cli_args *a)
Complete user input for 'cdr show'.
Definition cdr.c:4123
static void cli_show_channel(struct ast_cli_args *a)
Definition cdr.c:4208

References a, cli_complete_show(), CLI_GENERATE, CLI_INIT, cli_show_channel(), cli_show_channels(), CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, and ast_cli_entry::usage.

◆ handle_cli_status()

static char * handle_cli_status ( struct ast_cli_entry *  e,
int  cmd,
struct ast_cli_args *  a 
)
static

Definition at line 4298 of file cdr.c.

4299{
4300 struct cdr_beitem *beitem = NULL;
4301 struct module_config *mod_cfg;
4302 int cnt = 0;
4303 long nextbatchtime = 0;
4304
4305 switch (cmd) {
4306 case CLI_INIT:
4307 e->command = "cdr show status";
4308 e->usage =
4309 "Usage: cdr show status\n"
4310 " Displays the Call Detail Record engine system status.\n";
4311 return NULL;
4312 case CLI_GENERATE:
4313 return NULL;
4314 }
4315
4316 if (a->argc > 3) {
4317 return CLI_SHOWUSAGE;
4318 }
4319
4320 mod_cfg = ao2_global_obj_ref(module_configs);
4321 if (!mod_cfg) {
4322 return CLI_FAILURE;
4323 }
4324
4325 ast_cli(a->fd, "\n");
4326 ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
4327 ast_cli(a->fd, "----------------------------------\n");
4328 ast_cli(a->fd, " Logging: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) ? "Enabled" : "Disabled");
4329 ast_cli(a->fd, " Mode: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE) ? "Batch" : "Simple");
4330 if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4331 ast_cli(a->fd, " Log calls by default: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_CHANNEL_DEFAULT_ENABLED) ? "Yes" : "No");
4332 ast_cli(a->fd, " Log unanswered calls: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) ? "Yes" : "No");
4333 ast_cli(a->fd, " Log congestion: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION) ? "Yes" : "No");
4334 ast_cli(a->fd, " Ignore bridging changes: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_STATE_CHANGES) ? "Yes" : "No");
4335 ast_cli(a->fd, " Ignore dial state changes: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_DIAL_CHANGES) ? "Yes" : "No");
4336 ast_cli(a->fd, " Cancel disposition enabled: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_CANCEL_DISPOSITION_ENABLED) ? "Yes" : "No");
4337 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4338 ast_cli(a->fd, "* Batch Mode Settings\n");
4339 ast_cli(a->fd, " -------------------\n");
4340 if (batch)
4341 cnt = batch->size;
4342 if (cdr_sched > -1)
4343 nextbatchtime = ast_sched_when(sched, cdr_sched);
4344 ast_cli(a->fd, " Safe shutdown: %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN) ? "Enabled" : "Disabled");
4345 ast_cli(a->fd, " Threading model: %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SCHEDULER_ONLY) ? "Scheduler only" : "Scheduler plus separate threads");
4346 ast_cli(a->fd, " Current batch size: %d record%s\n", cnt, ESS(cnt));
4347 ast_cli(a->fd, " Maximum batch size: %u record%s\n", mod_cfg->general->batch_settings.size, ESS(mod_cfg->general->batch_settings.size));
4348 ast_cli(a->fd, " Maximum batch time: %u second%s\n", mod_cfg->general->batch_settings.time, ESS(mod_cfg->general->batch_settings.time));
4349 ast_cli(a->fd, " Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
4350 }
4351 ast_cli(a->fd, "* Registered Backends\n");
4352 ast_cli(a->fd, " -------------------\n");
4354 if (AST_RWLIST_EMPTY(&be_list)) {
4355 ast_cli(a->fd, " (none)\n");
4356 } else {
4357 AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
4358 ast_cli(a->fd, " %s%s\n", beitem->name, beitem->suspended ? " (suspended) " : "");
4359 }
4360 }
4362 ast_cli(a->fd, "\n");
4363 }
4364
4365 ao2_cleanup(mod_cfg);
4366 return CLI_SUCCESS;
4367}
static int cdr_sched
Definition cdr.c:457
@ CDR_UNANSWERED
Definition cdr.h:222
@ CDR_IGNORE_STATE_CHANGES
Definition cdr.h:228
@ CDR_IGNORE_DIAL_CHANGES
Definition cdr.h:229
#define ESS(x)
Definition cli.h:59
#define CLI_FAILURE
Definition cli.h:46
#define AST_RWLIST_EMPTY
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition linkedlists.h:78
long ast_sched_when(struct ast_sched_context *con, int id)
Returns the number of seconds before an event takes place.
Definition sched.c:851

References a, ao2_cleanup, ao2_global_obj_ref, ast_cli(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_sched_when(), ast_test_flag, batch, BATCH_MODE_SAFE_SHUTDOWN, BATCH_MODE_SCHEDULER_ONLY, ast_cdr_config::batch_settings, CDR_BATCHMODE, CDR_CANCEL_DISPOSITION_ENABLED, CDR_CHANNEL_DEFAULT_ENABLED, CDR_CONGESTION, CDR_ENABLED, CDR_IGNORE_DIAL_CHANGES, CDR_IGNORE_STATE_CHANGES, cdr_sched, CDR_UNANSWERED, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ESS, module_config::general, cdr_beitem::name, NULL, ast_cdr_config::settings, ast_cdr_config::batch_settings::settings, ast_cdr_config::batch_settings::size, cdr_batch::size, cdr_beitem::suspended, ast_cdr_config::batch_settings::time, and ast_cli_entry::usage.

◆ handle_cli_submit()

static char * handle_cli_submit ( struct ast_cli_entry *  e,
int  cmd,
struct ast_cli_args *  a 
)
static

Definition at line 4369 of file cdr.c.

4370{
4371 struct module_config *mod_cfg;
4372
4373 switch (cmd) {
4374 case CLI_INIT:
4375 e->command = "cdr submit";
4376 e->usage =
4377 "Usage: cdr submit\n"
4378 "Posts all pending batched CDR data to the configured CDR\n"
4379 "backend engine modules.\n";
4380 return NULL;
4381 case CLI_GENERATE:
4382 return NULL;
4383 }
4384 if (a->argc > 2) {
4385 return CLI_SHOWUSAGE;
4386 }
4387
4388 mod_cfg = ao2_global_obj_ref(module_configs);
4389 if (!mod_cfg) {
4390 return CLI_FAILURE;
4391 }
4392
4393 if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4394 ast_cli(a->fd, "Cannot submit CDR batch: CDR engine disabled.\n");
4395 } else if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4396 ast_cli(a->fd, "Cannot submit CDR batch: batch mode not enabled.\n");
4397 } else {
4399 ast_cli(a->fd, "Submitted CDRs to backend engines for processing. This may take a while.\n");
4400 }
4401 ao2_cleanup(mod_cfg);
4402
4403 return CLI_SUCCESS;
4404}

References a, ao2_cleanup, ao2_global_obj_ref, ast_cli(), ast_test_flag, CDR_BATCHMODE, CDR_ENABLED, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, module_config::general, NULL, ast_cdr_config::settings, start_batch_mode(), and ast_cli_entry::usage.

◆ handle_dial_message()

static void handle_dial_message ( void *  data,
struct stasis_subscription *  sub,
struct stasis_message *  message 
)
static

Handler for Stasis-Core dial messages.

Parameters
dataPassed on
subThe stasis subscription for this message callback
messageThe message

Definition at line 2214 of file cdr.c.

2215{
2216 struct cdr_object *cdr;
2219 struct ast_channel_snapshot *peer;
2220 struct cdr_object *it_cdr;
2221 struct ast_json *dial_status_blob;
2222 const char *dial_status = NULL;
2223 int res = 1;
2224
2225 caller = ast_multi_channel_blob_get_channel(payload, "caller");
2226 peer = ast_multi_channel_blob_get_channel(payload, "peer");
2227 if (!peer && !caller) {
2228 return;
2229 }
2230
2231 if (peer && filter_channel_snapshot(peer)) {
2232 return;
2233 }
2234
2235 if (caller && filter_channel_snapshot(caller)) {
2236 return;
2237 }
2238
2239 dial_status_blob = ast_json_object_get(ast_multi_channel_blob_get_json(payload), "dialstatus");
2240 if (dial_status_blob) {
2241 dial_status = ast_json_string_get(dial_status_blob);
2242 }
2243
2244 CDR_DEBUG("Dial %s message for %s, %s: %u.%08u\n",
2245 ast_strlen_zero(dial_status) ? "Begin" : "End",
2246 caller ? caller->base->name : "(none)",
2247 peer ? peer->base->name : "(none)",
2248 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2249 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2250
2251 /* Figure out who is running this show */
2252 if (caller) {
2254 } else {
2256 }
2257 if (!cdr) {
2258 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->base->name : peer->base->name);
2259 ast_assert(0);
2260 return;
2261 }
2262
2263 ao2_lock(cdr);
2264 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2266 if (ast_strlen_zero(dial_status)) {
2267 if (!it_cdr->fn_table->process_dial_begin) {
2268 continue;
2269 }
2271 CDR_DEBUG("%p - Ignoring Dial Begin message\n", it_cdr);
2272 continue;
2273 }
2274 CDR_DEBUG("%p - Processing Dial Begin message for channel %s, peer %s\n",
2275 it_cdr,
2276 caller ? caller->base->name : "(none)",
2277 peer ? peer->base->name : "(none)");
2278 res &= it_cdr->fn_table->process_dial_begin(it_cdr,
2279 caller,
2280 peer);
2281 } else if (dial_status_end(dial_status)) {
2282 if (!it_cdr->fn_table->process_dial_end) {
2283 continue;
2284 }
2286 /*
2287 * Once a dial has been answered, later non-answer Dial End events
2288 * must not downgrade the CDR disposition.
2289 */
2290 if (it_cdr->disposition != AST_CDR_ANSWERED) {
2291 it_cdr->disposition = dial_status_to_disposition(dial_status);
2292 }
2293 CDR_DEBUG("%p - Handling disposition only (%s)\n", it_cdr, dial_status);
2294 continue;
2295 }
2296 CDR_DEBUG("%p - Processing Dial End message for channel %s, peer %s\n",
2297 it_cdr,
2298 caller ? caller->base->name : "(none)",
2299 peer ? peer->base->name : "(none)");
2300 it_cdr->fn_table->process_dial_end(it_cdr,
2301 caller,
2302 peer,
2303 dial_status);
2304 }
2305 }
2306
2307 /* If we're ignoring dial changes, don't allow multiple CDRs for this channel. */
2308 if (!dial_changes_ignored) {
2309 /* If no CDR handled a dial begin message, make a new one */
2310 if (res && ast_strlen_zero(dial_status)) {
2311 struct cdr_object *new_cdr;
2312
2314 if (new_cdr) {
2315 new_cdr->fn_table->process_dial_begin(new_cdr, caller, peer);
2316 }
2317 }
2318 }
2319
2320 ao2_unlock(cdr);
2321 ao2_cleanup(cdr);
2322}
static int dial_changes_ignored
Definition cdr.c:312
static int dial_status_end(const char *dialstatus)
Definition cdr.c:2199
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_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.
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
Abstract JSON element (object, array, string, int, ...).
A multi channel blob data structure for multi_channel_blob stasis messages.
int(*const process_dial_end)(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
Process the end of a dial. At the end of a dial, a CDR can be transitioned into one of two states - D...
Definition cdr.c:584
int(*const process_dial_begin)(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
Process the beginning of a dial. A dial message implies one of two things: The cdr_object's Party A h...
Definition cdr.c:566

References active_cdrs_master, ao2_cleanup, ao2_find, ao2_lock, ao2_unlock, ast_assert, AST_CDR_ANSWERED, ast_json_object_get(), ast_json_string_get(), ast_log, AST_LOG_WARNING, ast_multi_channel_blob_get_channel(), ast_multi_channel_blob_get_json(), ast_strlen_zero(), ast_channel_snapshot::base, ast_channel_snapshot::caller, CDR_DEBUG, cdr_object_create_and_append(), dial_changes_ignored, dial_status_end(), dial_status_to_disposition(), cdr_object::disposition, filter_channel_snapshot(), cdr_object::fn_table, cdr_object::lastevent, ast_channel_snapshot_base::name, cdr_object::next, NULL, OBJ_SEARCH_KEY, ast_channel_snapshot::peer, cdr_object_fn_table::process_dial_begin, cdr_object_fn_table::process_dial_end, cdr_object::start, stasis_message_data(), stasis_message_timestamp(), and ast_channel_snapshot_base::uniqueid.

Referenced by load_module().

◆ handle_parked_call_message()

static void handle_parked_call_message ( void *  data,
struct stasis_subscription *  sub,
struct stasis_message *  message 
)
static

Handler for when a channel is parked.

Parameters
dataPassed on
subThe stasis subscription for this message callback
messageThe message about who got parked

Definition at line 2890 of file cdr.c.

2892{
2894 struct ast_channel_snapshot *channel = payload->parkee;
2895 struct cdr_object *cdr;
2896 int unhandled = 1;
2897 struct cdr_object *it_cdr;
2898
2899 /* Anything other than getting parked will be handled by other updates */
2900 if (payload->event_type != PARKED_CALL) {
2901 return;
2902 }
2903
2904 /* No one got parked? */
2905 if (!channel) {
2906 return;
2907 }
2908
2909 if (filter_channel_snapshot(channel)) {
2910 return;
2911 }
2912
2913 CDR_DEBUG("Parked Call message for channel %s: %u.%08u\n",
2914 channel->base->name,
2915 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2916 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2917
2919 if (!cdr) {
2920 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2921 ast_assert(0);
2922 return;
2923 }
2924
2925 ao2_lock(cdr);
2926
2927 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2929 if (it_cdr->fn_table->process_parked_channel) {
2930 unhandled &= it_cdr->fn_table->process_parked_channel(it_cdr, payload);
2931 }
2932 }
2933
2934 if (unhandled) {
2935 /* Nothing handled the message - we need a new one! */
2936 struct cdr_object *new_cdr;
2937
2939 if (new_cdr) {
2940 /* As the new CDR is created in the single state, it is guaranteed
2941 * to have a function for the parked call message and will handle
2942 * the message */
2943 new_cdr->fn_table->process_parked_channel(new_cdr, payload);
2944 }
2945 }
2946
2947 ao2_unlock(cdr);
2948
2949 ao2_cleanup(cdr);
2950}
@ PARKED_CALL
Definition parking.h:47
A parked call message payload.
Definition parking.h:59
enum ast_parked_call_event_type event_type
Definition parking.h:62

References active_cdrs_master, ao2_cleanup, ao2_find, ao2_lock, ao2_unlock, ast_assert, ast_log, AST_LOG_WARNING, ast_channel_snapshot::base, CDR_DEBUG, cdr_object_create_and_append(), ast_parked_call_payload::event_type, filter_channel_snapshot(), ast_channel_snapshot_base::name, cdr_object::next, OBJ_SEARCH_KEY, PARKED_CALL, ast_parked_call_payload::parkee, cdr_object::start, stasis_message_data(), stasis_message_timestamp(), and ast_channel_snapshot_base::uniqueid.

Referenced by load_module().

◆ handle_parking_bridge_enter_message()

static void handle_parking_bridge_enter_message ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel,
const struct timeval *  event_time 
)
static

Handle entering into a parking bridge.

Parameters
cdrThe CDR to operate on
bridgeThe bridge the channel just entered
channelThe channel snapshot
event_time

Definition at line 2726 of file cdr.c.

2730{
2731 int res = 1;
2732 struct cdr_object *it_cdr;
2733 struct cdr_object *new_cdr;
2734
2735 ao2_lock(cdr);
2736
2737 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2738 it_cdr->lastevent = *event_time;
2739
2740 if (it_cdr->fn_table->process_parking_bridge_enter) {
2741 res &= it_cdr->fn_table->process_parking_bridge_enter(it_cdr, bridge, channel);
2742 }
2743 if (it_cdr->fn_table->process_party_a) {
2744 CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
2745 channel->base->name);
2746 it_cdr->fn_table->process_party_a(it_cdr, channel);
2747 }
2748 }
2749
2750 if (res) {
2751 /* No one handled it - we need a new one! */
2752 new_cdr = cdr_object_create_and_append(cdr, event_time);
2753 if (new_cdr) {
2754 /* Let the single state transition us to Parked */
2756 new_cdr->fn_table->process_parking_bridge_enter(new_cdr, bridge, channel);
2757 }
2758 }
2759 ao2_unlock(cdr);
2760}

References ao2_lock, ao2_unlock, ast_channel_snapshot::base, cdr_object::bridge, CDR_DEBUG, cdr_object_create_and_append(), cdr_object_transition_state(), ast_channel_snapshot_base::name, cdr_object::next, single_state_fn_table, and cdr_object::start.

Referenced by handle_bridge_enter_message().

◆ handle_standard_bridge_enter_message()

static void handle_standard_bridge_enter_message ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel,
const struct timeval *  event_time 
)
static

Handle a bridge enter message for a 'normal' bridge.

Parameters
cdrThe CDR to operate on
bridgeThe bridge the channel just entered
channelThe channel snapshot
event_time

Definition at line 2768 of file cdr.c.

2772{
2774 struct cdr_object *it_cdr;
2775 struct cdr_object *new_cdr;
2776 struct cdr_object *handled_cdr = NULL;
2777
2778 ao2_lock(cdr);
2779
2780try_again:
2781 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2782 it_cdr->lastevent = *event_time;
2783
2784 if (it_cdr->fn_table->process_party_a) {
2785 CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
2786 channel->base->name);
2787 it_cdr->fn_table->process_party_a(it_cdr, channel);
2788 }
2789
2790 /* Notify all states that they have entered a bridge */
2791 if (it_cdr->fn_table->process_bridge_enter) {
2792 CDR_DEBUG("%p - Processing bridge enter for %s\n", it_cdr,
2793 channel->base->name);
2794 result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
2795 switch (result) {
2797 /* Fall through */
2799 if (!handled_cdr) {
2801 }
2802 break;
2804 /* Pass */
2805 break;
2807 /* We didn't win on any - end this CDR. If someone else comes in later
2808 * that is Party B to this CDR, it can re-activate this CDR.
2809 */
2810 if (!handled_cdr) {
2812 }
2814 break;
2815 }
2816 }
2817 }
2818
2819 /* Create the new matchings, but only for either:
2820 * * The first CDR in the chain that handled it. This avoids issues with
2821 * forked CDRs.
2822 * * If no one handled it, the last CDR in the chain. This would occur if
2823 * a CDR joined a bridge and it wasn't Party A for anyone. We still need
2824 * to make pairings with everyone in the bridge.
2825 */
2826 if (handled_cdr) {
2828 } else {
2829 /* Nothing handled it - we need a new one! */
2830 new_cdr = cdr_object_create_and_append(cdr, event_time);
2831 if (new_cdr) {
2832 /* This is guaranteed to succeed: the new CDR is created in the single state
2833 * and will be able to handle the bridge enter message
2834 */
2835 goto try_again;
2836 }
2837 }
2838 ao2_unlock(cdr);
2839}
process_bridge_enter_results
Return types for process_bridge_enter functions.
Definition cdr.c:495
static void handle_bridge_pairings(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge)
Handle creating bridge pairings for the cdr_object that just entered a bridge.
Definition cdr.c:2700
static PGresult * result
Definition cel_pgsql.c:84

References ao2_lock, ao2_unlock, ast_channel_snapshot::base, cdr_object::bridge, BRIDGE_ENTER_NEED_CDR, BRIDGE_ENTER_NO_PARTY_B, BRIDGE_ENTER_OBTAINED_PARTY_B, BRIDGE_ENTER_ONLY_PARTY, CDR_DEBUG, cdr_object_create_and_append(), cdr_object_finalize(), handle_bridge_pairings(), ast_channel_snapshot_base::name, cdr_object::next, NULL, result, and cdr_object::start.

Referenced by handle_bridge_enter_message().

◆ init_batch()

static int init_batch ( void  )
static
Note
Don't call without cdr_batch_lock

Definition at line 3891 of file cdr.c.

3892{
3893 /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
3894 if (!(batch = ast_malloc(sizeof(*batch))))
3895 return -1;
3896
3897 reset_batch();
3898
3899 return 0;
3900}
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191

References ast_malloc, batch, and reset_batch().

Referenced by cdr_detach().

◆ is_cdr_flag_set()

static int is_cdr_flag_set ( unsigned int  cdr_flag)
static

◆ load_module()

static int load_module ( void  )
static

Definition at line 4679 of file cdr.c.

4680{
4681 struct module_config *mod_cfg = NULL;
4682 if (process_config(0)) {
4684 }
4685
4686 cdr_topic = stasis_topic_create("cdr:aggregator");
4687 if (!cdr_topic) {
4689 }
4690
4692 if (!stasis_router) {
4694 }
4697
4698 if (STASIS_MESSAGE_TYPE_INIT(cdr_sync_message_type)) {
4700 }
4701
4702 mod_cfg = ao2_global_obj_ref(module_configs);
4703
4705
4706 /* Always process dial messages, because even if we ignore most of it, we do want the dial status for the disposition. */
4708 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_DIAL_CHANGES)) {
4710 } else {
4712 CDR_DEBUG("Dial messages will be mostly ignored\n");
4713 }
4714
4715 /* If explicitly instructed to ignore call state changes, then ignore bridging events, parking, etc. */
4716 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_STATE_CHANGES)) {
4720 } else {
4721 CDR_DEBUG("All bridge and parking messages will be ignored\n");
4722 }
4723
4725
4726 if (mod_cfg) {
4727 ao2_cleanup(mod_cfg);
4728 } else {
4729 ast_log(LOG_WARNING, "Unable to obtain CDR configuration during module load?\n");
4730 }
4731
4734 if (!active_cdrs_master) {
4736 }
4738
4741 if (!active_cdrs_all) {
4743 }
4745
4747 if (!sched) {
4748 ast_log(LOG_ERROR, "Unable to create schedule context.\n");
4750 }
4751
4754
4756}
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition clicompat.c:13
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
Register a container for CLI stats and integrity check.
#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
static void handle_parked_call_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for when a channel is parked.
Definition cdr.c:2890
static int process_config(int reload)
Definition cdr.c:4497
static void cdr_all_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition cdr.c:4629
static int cdr_all_hash_fn(const void *obj, const int flags)
Definition cdr.c:994
static int cdr_master_cmp_fn(void *obj, void *arg, int flags)
Definition cdr.c:960
static void handle_bridge_leave_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for when a channel leaves a bridge.
Definition cdr.c:2543
static void handle_channel_snapshot_update_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for channel snapshot update messages.
Definition cdr.c:2405
static void handle_bridge_enter_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition cdr.c:2848
static void handle_cdr_sync_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for a synchronization message.
Definition cdr.c:2958
static void cdr_master_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition cdr.c:4604
static int cdr_all_cmp_fn(void *obj, void *arg, int flags)
Definition cdr.c:1018
static void handle_dial_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for Stasis-Core dial messages.
Definition cdr.c:2214
static void cdr_engine_shutdown(void)
Definition cdr.c:4546
static int cdr_master_hash_fn(const void *obj, const int flags)
Definition cdr.c:936
#define AST_NUM_CHANNEL_BUCKETS
Definition channel.h:157
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
struct stasis_message_type * ast_parked_call_type(void)
accessor for the parked call stasis message type
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.
@ AST_MODULE_LOAD_FAILURE
Module could not be loaded properly.
Definition module.h:102
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition sched.c:238
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition stasis.c:684
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1524
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
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.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL

References active_cdrs_all, active_cdrs_master, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_cleanup, ao2_container_alloc_hash, ao2_container_register(), ao2_global_obj_ref, ARRAY_LEN, ast_channel_dial_type(), ast_channel_entered_bridge_type(), ast_channel_left_bridge_type(), ast_channel_snapshot_type(), ast_cli_register_multiple, ast_log, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, AST_NUM_CHANNEL_BUCKETS, ast_parked_call_type(), ast_register_atexit(), ast_sched_context_create(), AST_TASKPROCESSOR_HIGH_WATER_LEVEL, ast_test_flag, cdr_all_cmp_fn(), cdr_all_hash_fn(), cdr_all_print_fn(), CDR_DEBUG, cdr_engine_shutdown(), CDR_IGNORE_DIAL_CHANGES, CDR_IGNORE_STATE_CHANGES, cdr_master_cmp_fn(), cdr_master_hash_fn(), cdr_master_print_fn(), cdr_toggle_runtime_options(), cdr_topic, cli_commands, dial_changes_ignored, module_config::general, handle_bridge_enter_message(), handle_bridge_leave_message(), handle_cdr_sync_message(), handle_channel_snapshot_update_message(), handle_dial_message(), handle_parked_call_message(), LOG_ERROR, LOG_WARNING, NULL, process_config(), ast_cdr_config::settings, stasis_message_router_add(), stasis_message_router_create, stasis_message_router_set_congestion_limits(), STASIS_MESSAGE_TYPE_INIT, stasis_router, and stasis_topic_create().

◆ module_config_alloc()

static void * module_config_alloc ( void  )
static

Create a new module config object.

Definition at line 404 of file cdr.c.

405{
406 struct module_config *mod_cfg;
408
409 mod_cfg = ao2_alloc(sizeof(*mod_cfg), module_config_destructor);
410 if (!mod_cfg) {
411 return NULL;
412 }
413
414 cdr_config = ao2_alloc(sizeof(*cdr_config), NULL);
415 if (!cdr_config) {
416 ao2_ref(cdr_config, -1);
417 return NULL;
418 }
419 mod_cfg->general = cdr_config;
420
421 return mod_cfg;
422}
static void module_config_destructor(void *obj)
Dispose of a module config object.
Definition cdr.c:393
static const char cdr_config[]
Definition cdr_radius.c:86

References ao2_alloc, ao2_ref, cdr_config, module_config::general, module_config_destructor(), and NULL.

Referenced by process_config().

◆ module_config_destructor()

static void module_config_destructor ( void *  obj)
static

Dispose of a module config object.

Definition at line 393 of file cdr.c.

394{
395 struct module_config *cfg = obj;
396
397 if (!cfg) {
398 return;
399 }
400 ao2_ref(cfg->general, -1);
401}

References ao2_ref, and module_config::general.

Referenced by module_config_alloc().

◆ module_config_post_apply()

static void module_config_post_apply ( void  )
static

Definition at line 380 of file cdr.c.

381{
382 struct module_config *mod_cfg;
383
384 mod_cfg = ao2_global_obj_ref(module_configs);
385 if (!mod_cfg) {
386 return;
387 }
388 cdr_set_debug_mode(mod_cfg);
389 ao2_cleanup(mod_cfg);
390}

References ao2_cleanup, ao2_global_obj_ref, and cdr_set_debug_mode.

◆ parked_state_process_bridge_leave()

static int parked_state_process_bridge_leave ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel 
)
static

◆ post_cdr()

static void post_cdr ( struct ast_cdr *  cdr)
static

Definition at line 3661 of file cdr.c.

3662{
3663 struct module_config *mod_cfg;
3664 struct cdr_beitem *i;
3665
3666 mod_cfg = ao2_global_obj_ref(module_configs);
3667 if (!mod_cfg) {
3668 return;
3669 }
3670
3671 for (; cdr ; cdr = cdr->next) {
3672 /* For people, who don't want to see unanswered single-channel events */
3673 if (!ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) &&
3676 ast_debug(1, "Skipping CDR for %s since we weren't answered\n", cdr->channel);
3677 continue;
3678 }
3679
3680 /* Modify CDR's */
3683 i->be(cdr);
3684 }
3686
3688 continue;
3689 }
3692 if (!i->suspended) {
3693 i->be(cdr);
3694 }
3695 }
3697 }
3698 ao2_cleanup(mod_cfg);
3699}
@ AST_CDR_FLAG_DISABLE
Definition cdr.h:245

References ao2_cleanup, ao2_global_obj_ref, AST_CDR_ANSWERED, AST_CDR_FLAG_DISABLE, ast_debug, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strlen_zero(), ast_test_flag, cdr_beitem::be, CDR_UNANSWERED, ast_cdr::channel, ast_cdr::disposition, ast_cdr::dstchannel, module_config::general, cdr_beitem::list, ast_cdr::next, ast_cdr_config::settings, and cdr_beitem::suspended.

Referenced by cdr_detach(), and do_batch_backend_process().

◆ process_config()

static int process_config ( int  reload)
static

Definition at line 4497 of file cdr.c.

4498{
4499 if (!reload) {
4500 if (aco_info_init(&cfg_info)) {
4501 return 1;
4502 }
4503
4519 }
4520
4521 if (aco_process_config(&cfg_info, reload) == ACO_PROCESS_ERROR) {
4522 struct module_config *mod_cfg;
4523
4524 if (reload) {
4525 return 1;
4526 }
4527
4528 /* If we couldn't process the configuration and this wasn't a reload,
4529 * create a default config
4530 */
4531 mod_cfg = module_config_alloc();
4532 if (!mod_cfg
4533 || aco_set_defaults(&general_option, "general", mod_cfg->general)) {
4534 ao2_cleanup(mod_cfg);
4535 return 1;
4536 }
4537 ast_log(LOG_NOTICE, "Failed to process CDR configuration; using defaults\n");
4538 ao2_global_obj_replace_unref(module_configs, mod_cfg);
4539 cdr_set_debug_mode(mod_cfg);
4540 ao2_cleanup(mod_cfg);
4541 }
4542
4543 return 0;
4544}
#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 DEFAULT_BATCH_SIZE
Definition cdr.c:299
#define MAX_BATCH_SIZE
Definition cdr.c:300
#define DEFAULT_BATCHMODE
Definition cdr.c:290
#define DEFAULT_IGNORE_STATE_CHANGES
Definition cdr.c:296
#define DEFAULT_UNANSWERED
Definition cdr.c:291
static struct aco_type general_option
The type definition for general options.
Definition cdr.c:334
#define MAX_BATCH_TIME
Definition cdr.c:302
static struct aco_type * general_options[]
Definition cdr.c:378
#define DEFAULT_INITIATED_SECONDS
Definition cdr.c:294
#define DEFAULT_IGNORE_DIAL_CHANGES
Definition cdr.c:297
#define DEFAULT_BATCH_SAFE_SHUTDOWN
Definition cdr.c:304
#define DEFAULT_BATCH_TIME
Definition cdr.c:301
#define DEFAULT_BATCH_SCHEDULER_ONLY
Definition cdr.c:303
#define DEFAULT_CHANNEL_ENABLED
Definition cdr.c:295
#define DEFAULT_ENABLED
Definition cdr.c:289
static void * module_config_alloc(void)
Create a new module config object.
Definition cdr.c:404
#define DEFAULT_END_BEFORE_H_EXTEN
Definition cdr.c:293
static struct cdr_tds_config * settings
Definition cdr_tds.c:95
@ ACO_EXACT
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
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.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_BOOLFLAG_T
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag.
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.
static int reload(void)

References ACO_EXACT, aco_info_init(), aco_option_register, aco_process_config(), ACO_PROCESS_ERROR, aco_set_defaults(), ao2_cleanup, ao2_global_obj_replace_unref, ast_log, BATCH_MODE_SAFE_SHUTDOWN, BATCH_MODE_SCHEDULER_ONLY, CDR_BATCHMODE, CDR_CANCEL_DISPOSITION_ENABLED, CDR_CHANNEL_DEFAULT_ENABLED, CDR_CONGESTION, CDR_DEBUG, CDR_ENABLED, CDR_END_BEFORE_H_EXTEN, CDR_IGNORE_DIAL_CHANGES, CDR_IGNORE_STATE_CHANGES, CDR_INITIATED_SECONDS, cdr_set_debug_mode, CDR_UNANSWERED, DEFAULT_BATCH_SAFE_SHUTDOWN, DEFAULT_BATCH_SCHEDULER_ONLY, DEFAULT_BATCH_SIZE, DEFAULT_BATCH_TIME, DEFAULT_BATCHMODE, DEFAULT_CHANNEL_ENABLED, DEFAULT_ENABLED, DEFAULT_END_BEFORE_H_EXTEN, DEFAULT_IGNORE_DIAL_CHANGES, DEFAULT_IGNORE_STATE_CHANGES, DEFAULT_INITIATED_SECONDS, DEFAULT_UNANSWERED, FLDSET, module_config::general, general_option, general_options, LOG_NOTICE, MAX_BATCH_SIZE, MAX_BATCH_TIME, module_config_alloc(), OPT_BOOLFLAG_T, OPT_UINT_T, PARSE_IN_RANGE, reload(), settings, and ast_cdr_config::settings.

Referenced by load_module(), and reload_module().

◆ reload_module()

static int reload_module ( void  )
static

Definition at line 4798 of file cdr.c.

4799{
4800 struct module_config *old_mod_cfg;
4801 struct module_config *mod_cfg;
4802
4803 old_mod_cfg = ao2_global_obj_ref(module_configs);
4804
4805 if (!old_mod_cfg || process_config(1)) {
4806 ao2_cleanup(old_mod_cfg);
4807 return -1;
4808 }
4809
4810 mod_cfg = ao2_global_obj_ref(module_configs);
4811 if (!mod_cfg
4812 || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)
4813 || !ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4814 /* If batch mode used to be enabled, finalize the batch */
4815 if (ast_test_flag(&old_mod_cfg->general->settings, CDR_BATCHMODE)) {
4817 }
4818 }
4819 ao2_cleanup(mod_cfg);
4820
4821 ao2_cleanup(old_mod_cfg);
4823}

References ao2_cleanup, ao2_global_obj_ref, ast_test_flag, CDR_BATCHMODE, CDR_ENABLED, cdr_toggle_runtime_options(), finalize_batch_mode(), module_config::general, process_config(), and ast_cdr_config::settings.

◆ reset_batch()

static void reset_batch ( void  )
static
Note
Don't call without cdr_batch_lock

Definition at line 3883 of file cdr.c.

3884{
3885 batch->size = 0;
3886 batch->head = NULL;
3887 batch->tail = NULL;
3888}

References batch, cdr_batch::head, NULL, cdr_batch::size, and cdr_batch::tail.

Referenced by cdr_submit_batch(), and init_batch().

◆ set_variable()

static void set_variable ( struct varshead *  headp,
const char *  name,
const char *  value 
)
static

Definition at line 1364 of file cdr.c.

1365{
1366 struct ast_var_t *newvariable;
1367
1368 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1369 if (!strcasecmp(ast_var_name(newvariable), name)) {
1371 ast_var_delete(newvariable);
1372 break;
1373 }
1374 }
1376
1377 if (value && (newvariable = ast_var_assign(name, value))) {
1378 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1379 }
1380}
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.

References AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_var_assign, ast_var_delete(), ast_var_name(), ast_var_t::entries, name, and value.

Referenced by ast_cdr_setvar(), and cdr_object_update_cid().

◆ single_state_bridge_enter_comparison()

static int single_state_bridge_enter_comparison ( struct cdr_object *  cdr,
struct cdr_object *  cand_cdr 
)
static

Handle a comparison between our cdr_object and a cdr_object already in the bridge while in the Single state. The goal of this is to find a Party B for our CDR.

Parameters
cdrOur cdr_object in the Single state
cand_cdrThe cdr_object already in the Bridge state
Return values
0The cand_cdr had a Party A or Party B that we could use as our Party B
1No party in the cand_cdr could be used as our Party B

Definition at line 1796 of file cdr.c.

1798{
1799 struct cdr_object_snapshot *party_a;
1800
1801 /* Don't match on ourselves */
1802 if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
1803 return 1;
1804 }
1805
1806 /* Try the candidate CDR's Party A first */
1807 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
1808 if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
1809 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
1810 cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name);
1811 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
1812 cdr_all_relink(cdr);
1813 if (!cand_cdr->party_b.snapshot) {
1814 /* We just stole them - finalize their CDR. Note that this won't
1815 * transition their state, it just sets the end time and the
1816 * disposition - if we need to re-activate them later, we can.
1817 */
1818 cdr_object_finalize(cand_cdr);
1819 }
1820 return 0;
1821 }
1822
1823 /* Try their Party B, unless it's us */
1824 if (!cand_cdr->party_b.snapshot
1825 || !strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name)) {
1826 return 1;
1827 }
1828 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b);
1829 if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
1830 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
1831 cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name);
1832 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
1833 cdr_all_relink(cdr);
1834 return 0;
1835 }
1836
1837 return 1;
1838}

References ast_channel_snapshot::base, cdr_all_relink(), CDR_DEBUG, cdr_object_finalize(), cdr_object_pick_party_a(), cdr_object_snapshot_copy(), ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, and cdr_object_snapshot::snapshot.

Referenced by single_state_process_bridge_enter().

◆ single_state_init_function()

static void single_state_init_function ( struct cdr_object *  cdr)
static

Definition at line 1743 of file cdr.c.

1744{
1745 cdr->start = cdr->lastevent;
1747}

References cdr_object_check_party_a_answer(), cdr_object::lastevent, and cdr_object::start.

◆ single_state_process_bridge_enter()

static enum process_bridge_enter_results single_state_process_bridge_enter ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel 
)
static

Definition at line 1840 of file cdr.c.

1841{
1842 struct ao2_iterator it_cdrs;
1843 char *channel_id;
1844 int success = 0;
1845
1846 ast_string_field_set(cdr, bridge, bridge->uniqueid);
1847
1848 if (ao2_container_count(bridge->channels) == 1) {
1849 /* No one in the bridge yet but us! */
1852 }
1853
1854 for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
1855 !success && (channel_id = ao2_iterator_next(&it_cdrs));
1856 ao2_ref(channel_id, -1)) {
1858 struct cdr_object *cand_cdr;
1859
1861 if (!cand_cdr_master) {
1862 continue;
1863 }
1864
1867 /* Skip any records that are not in a bridge or in this bridge.
1868 * I'm not sure how that would happen, but it pays to be careful. */
1869 if (cand_cdr->fn_table != &bridge_state_fn_table ||
1870 strcmp(cdr->bridge, cand_cdr->bridge)) {
1871 continue;
1872 }
1873
1875 continue;
1876 }
1877 /* We successfully got a party B - break out */
1878 success = 1;
1879 break;
1880 }
1883 }
1885
1886 /* We always transition state, even if we didn't get a peer */
1888
1889 /* Success implies that we have a Party B */
1890 if (success) {
1892 }
1893
1895}
static int single_state_bridge_enter_comparison(struct cdr_object *cdr, struct cdr_object *cand_cdr)
Handle a comparison between our cdr_object and a cdr_object already in the bridge while in the Single...
Definition cdr.c:1796

References active_cdrs_master, ao2_cleanup, ao2_container_count(), ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_string_field_set, cdr_object::bridge, BRIDGE_ENTER_NO_PARTY_B, BRIDGE_ENTER_OBTAINED_PARTY_B, BRIDGE_ENTER_ONLY_PARTY, bridge_state_fn_table, cdr_object_transition_state(), ast_bridge_snapshot::channels, OBJ_SEARCH_KEY, single_state_bridge_enter_comparison(), cdr_object::start, and ast_bridge_snapshot::uniqueid.

◆ single_state_process_dial_begin()

static int single_state_process_dial_begin ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  caller,
struct ast_channel_snapshot *  peer 
)
static

Definition at line 1757 of file cdr.c.

1758{
1759 if (caller && !strcasecmp(cdr->party_a.snapshot->base->name, caller->base->name)) {
1760 base_process_party_a(cdr, caller);
1761 CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
1762 cdr->party_a.snapshot->base->name);
1763 cdr_object_swap_snapshot(&cdr->party_b, peer);
1764 cdr_all_relink(cdr);
1765 CDR_DEBUG("%p - Updated Party B %s snapshot\n", cdr,
1766 cdr->party_b.snapshot->base->name);
1767
1768 /* If we have two parties, lock the application that caused the
1769 * two parties to be associated. This prevents mid-call event
1770 * gosubs from perturbing the CDR application/data
1771 */
1773 } else if (!strcasecmp(cdr->party_a.snapshot->base->name, peer->base->name)) {
1774 /* We're the entity being dialed, i.e., outbound origination */
1775 base_process_party_a(cdr, peer);
1776 CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
1777 cdr->party_a.snapshot->base->name);
1778 }
1779
1781 return 0;
1782}

References AST_CDR_LOCK_APP, ast_set_flag, ast_channel_snapshot::base, base_process_party_a(), cdr_all_relink(), CDR_DEBUG, cdr_object_swap_snapshot(), cdr_object_transition_state(), dial_state_fn_table, cdr_object::flags, ast_channel_snapshot_base::name, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, and ast_cdr::start.

◆ single_state_process_parking_bridge_enter()

static int single_state_process_parking_bridge_enter ( struct cdr_object *  cdr,
struct ast_bridge_snapshot *  bridge,
struct ast_channel_snapshot *  channel 
)
static

Definition at line 1897 of file cdr.c.

1898{
1900 return 0;
1901}

References cdr_object_transition_state(), and parked_state_fn_table.

◆ single_state_process_party_b()

static void single_state_process_party_b ( struct cdr_object *  cdr,
struct ast_channel_snapshot *  snapshot 
)
static

Definition at line 1749 of file cdr.c.

1750{
1751 /* This should never happen! */
1753 ast_assert(0);
1754 return;
1755}

References ast_assert, NULL, cdr_object::party_b, and cdr_object_snapshot::snapshot.

◆ snapshot_cep_changed()

static int snapshot_cep_changed ( struct ast_channel_snapshot *  old_snapshot,
struct ast_channel_snapshot *  new_snapshot 
)
static

Return whether or not a channel has changed its state in the dialplan, subject to endbeforehexten logic.

Parameters
old_snapshotThe previous state
new_snapshotThe new state
Return values
0if the state has not changed
1if the state changed

Definition at line 1250 of file cdr.c.

1252{
1253 /* If we ignore hangup logic, don't indicate that we're executing anything new */
1256 return 0;
1257 }
1258
1259 /* When Party A is originated to an application and the application exits, the stack
1260 * will attempt to clear the application and restore the dummy originate application
1261 * of "AppDialX". Ignore application changes to AppDialX as a result.
1262 */
1263 if (strcmp(new_snapshot->dialplan->appl, old_snapshot->dialplan->appl)
1264 && strncasecmp(new_snapshot->dialplan->appl, "appdial", 7)
1265 && (strcmp(new_snapshot->dialplan->context, old_snapshot->dialplan->context)
1266 || strcmp(new_snapshot->dialplan->exten, old_snapshot->dialplan->exten)
1267 || new_snapshot->dialplan->priority != old_snapshot->dialplan->priority)) {
1268 return 1;
1269 }
1270
1271 return 0;
1272}

References ast_channel_snapshot_dialplan::appl, AST_SOFTHANGUP_HANGUP_EXEC, ast_test_flag, CDR_END_BEFORE_H_EXTEN, ast_channel_snapshot_dialplan::context, ast_channel_snapshot::dialplan, ast_channel_snapshot_dialplan::exten, is_cdr_flag_set(), ast_channel_snapshot_dialplan::priority, and ast_channel_snapshot::softhangup_flags.

Referenced by check_new_cdr_needed(), and dialed_pending_state_process_party_a().

◆ snapshot_is_dialed()

static int snapshot_is_dialed ( struct ast_channel_snapshot *  snapshot)
static

Return whether or not a ast_channel_snapshot is for a channel that was created as the result of a dial operation.

Return values
0the channel was not created as the result of a dial
1the channel was created as the result of a dial

Definition at line 1281 of file cdr.c.

1282{
1283 return (ast_test_flag(&snapshot->flags, AST_FLAG_OUTGOING)
1284 && !(ast_test_flag(&snapshot->flags, AST_FLAG_ORIGINATED)));
1285}
@ AST_FLAG_OUTGOING
Definition channel.h:1019
@ AST_FLAG_ORIGINATED
Definition channel.h:1059

References AST_FLAG_ORIGINATED, AST_FLAG_OUTGOING, ast_test_flag, and ast_channel_snapshot::flags.

Referenced by cdr_object_create_public_records(), cdr_object_pick_party_a(), cli_show_channel(), and cli_show_channels().

◆ start_batch_mode()

static void start_batch_mode ( void  )
static

Do not hold the batch lock while calling this function

Definition at line 3978 of file cdr.c.

3979{
3980 /* Prevent two deletes from happening at the same time */
3982 /* this is okay since we are not being called from within the scheduler */
3984 /* schedule the submission to occur ASAP (1 ms) */
3987
3988 /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
3992}
static int submit_scheduled_batch(const void *data)
Definition cdr.c:3957
static ast_mutex_t cdr_sched_lock
Definition cdr.c:458
#define ast_cond_signal(cond)
Definition lock.h:210
#define AST_SCHED_DEL(sched, id)
Remove a scheduler entry.
Definition sched.h:46
int ast_sched_add_variable(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result
Adds a scheduled event with rescheduling support.
Definition sched.c:526

References ast_cond_signal, ast_mutex_lock, ast_mutex_unlock, ast_sched_add_variable(), AST_SCHED_DEL, cdr_pending_cond, cdr_pending_lock, cdr_sched, cdr_sched_lock, NULL, and submit_scheduled_batch().

Referenced by cdr_detach(), cdr_enable_batch_mode(), and handle_cli_submit().

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL()

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( cdr_sync_message_type  )

A message type used to synchronize with the CDR topic.

◆ submit_scheduled_batch()

static int submit_scheduled_batch ( const void *  data)
static

Definition at line 3957 of file cdr.c.

3958{
3959 struct module_config *mod_cfg;
3960 int nextms;
3961
3963
3964 mod_cfg = ao2_global_obj_ref(module_configs);
3965 if (!mod_cfg) {
3966 return 0;
3967 }
3968
3969 /* Calculate the next scheduled interval */
3970 nextms = mod_cfg->general->batch_settings.time * 1000;
3971
3972 ao2_cleanup(mod_cfg);
3973
3974 return nextms;
3975}

References ao2_cleanup, ao2_global_obj_ref, ast_cdr_config::batch_settings, cdr_submit_batch(), module_config::general, and ast_cdr_config::batch_settings::time.

Referenced by start_batch_mode().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 4672 of file cdr.c.

4673{
4675
4676 return 0;
4677}

References destroy_subscriptions().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "CDR Engine" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_CORE, .requires = "extconfig", }
static

Definition at line 4832 of file cdr.c.

◆ active_cdrs_all

struct ao2_container* active_cdrs_all
static

A container of all active CDRs with a Party B indexed by Party B channel name.

Definition at line 472 of file cdr.c.

Referenced by ast_cdr_setuserfield(), cdr_all_relink(), cdr_all_unlink(), cdr_engine_shutdown(), handle_bridge_leave_message(), handle_channel_snapshot_update_message(), and load_module().

◆ active_cdrs_master

struct ao2_container* active_cdrs_master
static

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 4832 of file cdr.c.

◆ batch

struct cdr_batch * batch = NULL
static

◆ be_list

◆ bridge_state_fn_table

struct cdr_object_fn_table bridge_state_fn_table

The virtual table for the Bridged state.

A cdr_object enters this state when it receives notification that the channel has entered a bridge.

A cdr_object from this state can go to:

Definition at line 763 of file cdr.c.

763 {
764 .name = "Bridged",
765 .process_party_a = base_process_party_a,
766 .process_party_b = bridge_state_process_party_b,
767 .process_bridge_leave = bridge_state_process_bridge_leave,
768 .process_parked_channel = base_process_parked_channel,
769};
static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition cdr.c:2112
static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked_call_payload *parking_info)
Definition cdr.c:1721
static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition cdr.c:2125

Referenced by bridge_candidate_add_to_cdr(), cdr_object_party_b_left_bridge_cb(), dial_state_process_bridge_enter(), and single_state_process_bridge_enter().

◆ bridge_subscription

struct stasis_forward* bridge_subscription
static

Our subscription for bridges.

Definition at line 478 of file cdr.c.

Referenced by create_subscriptions(), and destroy_subscriptions().

◆ cdr_batch_lock

ast_mutex_t cdr_batch_lock = AST_MUTEX_INIT_VALUE
static

Lock protecting modifications to the batch queue.

Definition at line 462 of file cdr.c.

Referenced by cdr_detach(), and cdr_submit_batch().

◆ cdr_debug_enabled

int cdr_debug_enabled
static

Definition at line 311 of file cdr.c.

◆ cdr_pending_cond

ast_cond_t cdr_pending_cond
static

Definition at line 466 of file cdr.c.

Referenced by cdr_enable_batch_mode(), do_cdr(), finalize_batch_mode(), and start_batch_mode().

◆ cdr_pending_lock

ast_mutex_t cdr_pending_lock = AST_MUTEX_INIT_VALUE
static

These are used to wake up the CDR thread when there's work to do.

Definition at line 465 of file cdr.c.

Referenced by do_cdr(), and start_batch_mode().

◆ cdr_readonly_vars

const char* const cdr_readonly_vars[]
static

Definition at line 3296 of file cdr.c.

3296 {
3297 "clid",
3298 "src",
3299 "dst",
3300 "dcontext",
3301 "channel",
3302 "dstchannel",
3303 "lastapp",
3304 "lastdata",
3305 "start",
3306 "answer",
3307 "end",
3308 "duration",
3309 "billsec",
3310 "disposition",
3311 "amaflags",
3312 "accountcode",
3313 "uniqueid",
3314 "linkedid",
3315 "tenantid",
3316 "userfield",
3317 "sequence",
3318 NULL
3319};

Referenced by ast_cdr_serialize_variables(), and ast_cdr_setvar().

◆ cdr_sched

int cdr_sched = -1
static

Definition at line 457 of file cdr.c.

Referenced by handle_cli_status(), and start_batch_mode().

◆ cdr_sched_lock

ast_mutex_t cdr_sched_lock = AST_MUTEX_INIT_VALUE
static

Definition at line 458 of file cdr.c.

Referenced by start_batch_mode().

◆ cdr_thread

pthread_t cdr_thread = AST_PTHREADT_NULL
static

Definition at line 459 of file cdr.c.

Referenced by cdr_enable_batch_mode(), and finalize_batch_mode().

◆ cdr_topic

struct stasis_topic* cdr_topic
static

The parent topic for all topics we want to aggregate for CDRs.

Definition at line 487 of file cdr.c.

Referenced by cdr_engine_shutdown(), create_subscriptions(), and load_module().

◆ channel_subscription

struct stasis_forward* channel_subscription
static

Our subscription for channels.

Definition at line 481 of file cdr.c.

Referenced by create_subscriptions(), and destroy_subscriptions().

◆ cli_commands

struct ast_cli_entry cli_commands[]
static

Definition at line 4406 of file cdr.c.

4406 {
4407 AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data"),
4408 AST_CLI_DEFINE(handle_cli_status, "Display the CDR status"),
4409 AST_CLI_DEFINE(handle_cli_show, "Display active CDRs for channels"),
4410 AST_CLI_DEFINE(handle_cli_debug, "Enable debugging in the CDR engine"),
4411};
static char * handle_cli_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition cdr.c:4268
static char * handle_cli_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition cdr.c:4082
static char * handle_cli_submit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition cdr.c:4369
static char * handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition cdr.c:4298
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by cdr_engine_shutdown(), and load_module().

◆ dial_changes_ignored

int dial_changes_ignored
static

Definition at line 312 of file cdr.c.

Referenced by handle_dial_message(), and load_module().

◆ dial_state_fn_table

struct cdr_object_fn_table dial_state_fn_table

The virtual table for the Dial state.

A cdr_object that has begun a dial operation. This state is entered when the Party A for a CDR is determined to be dialing out to a Party B or when a CDR is for an originated channel (in which case the Party A information is the originated channel, and there is no Party B).

A cdr_object from this state can go in any of the following states:

Definition at line 708 of file cdr.c.

708 {
709 .name = "Dial",
710 .process_party_a = base_process_party_a,
711 .process_party_b = dial_state_process_party_b,
712 .process_dial_begin = dial_state_process_dial_begin,
713 .process_dial_end = dial_state_process_dial_end,
714 .process_bridge_enter = dial_state_process_bridge_enter,
715 .process_bridge_leave = base_process_bridge_leave,
716};
static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition cdr.c:1705
static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
Definition cdr.c:1958
static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition cdr.c:1906
static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
Definition cdr.c:1920
static enum process_bridge_enter_results dial_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition cdr.c:1990

Referenced by dialed_pending_state_process_bridge_enter(), and single_state_process_dial_begin().

◆ dialed_pending_state_fn_table

struct cdr_object_fn_table dialed_pending_state_fn_table

The virtual table for the Dialed Pending state.

A cdr_object that has successfully finished a dial operation, but we don't know what they're going to do yet. It's theoretically possible to dial a party and then have that party not be bridged with the caller; likewise, an origination can complete and the channel go off and execute dialplan. The pending state acts as a bridge between either:

  • Entering a bridge
  • Getting a new CDR for new dialplan execution
  • Switching from being originated to executing dialplan

A cdr_object from this state can go in any of the following states:

Definition at line 741 of file cdr.c.

741 {
742 .name = "DialedPending",
743 .process_party_a = dialed_pending_state_process_party_a,
744 .process_dial_begin = dialed_pending_state_process_dial_begin,
745 .process_bridge_enter = dialed_pending_state_process_bridge_enter,
746 .process_parking_bridge_enter = dialed_pending_state_process_parking_bridge_enter,
747 .process_bridge_leave = base_process_bridge_leave,
748 .process_parked_channel = base_process_parked_channel,
749};
static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
Definition cdr.c:2102
static int dialed_pending_state_process_parking_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition cdr.c:2092
static enum process_bridge_enter_results dialed_pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition cdr.c:2086
static int dialed_pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition cdr.c:2061

Referenced by dial_state_process_dial_end().

◆ finalized_state_fn_table

struct cdr_object_fn_table finalized_state_fn_table

The virtual table for the finalized state.

Once in the finalized state, the CDR is done. No modifications can be made to the CDR.

Definition at line 798 of file cdr.c.

798 {
799 .name = "Finalized",
800 .init_function = finalized_state_init_function,
801 .process_party_a = finalized_state_process_party_a,
802 .process_bridge_enter = base_process_bridge_enter,
803};
static void finalized_state_init_function(struct cdr_object *cdr)
Definition cdr.c:2154
static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition cdr.c:2159
static enum process_bridge_enter_results base_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition cdr.c:1715

Referenced by ast_cdr_clear_property(), ast_cdr_fork(), ast_cdr_set_property(), ast_cdr_setuserfield(), ast_cdr_setvar(), bridge_state_process_bridge_leave(), bridge_state_process_party_b(), cdr_object_check_party_a_hangup(), cdr_object_dispatch_all_cb(), cdr_object_update_party_b_userfield_cb(), dial_state_process_dial_end(), dial_state_process_party_b(), dialed_pending_state_process_dial_begin(), dialed_pending_state_process_party_a(), and parked_state_process_bridge_leave().

◆ general_option

struct aco_type general_option
static

The type definition for general options.

Definition at line 334 of file cdr.c.

334 {
335 .type = ACO_GLOBAL,
336 .name = "general",
337 .item_offset = offsetof(struct module_config, general),
338 .category = "general",
339 .category_match = ACO_WHITELIST_EXACT,
340};
@ ACO_GLOBAL
@ ACO_WHITELIST_EXACT

Referenced by process_config().

◆ general_options

struct aco_type* general_options[] = ACO_TYPES(&general_option)
static

Definition at line 378 of file cdr.c.

Referenced by process_config().

◆ global_cdr_sequence

int global_cdr_sequence = 0
static

The global sequence counter used for CDRs.

Definition at line 453 of file cdr.c.

Referenced by cdr_object_alloc().

◆ ignore_categories

const char* ignore_categories[]
static

Config sections used by existing modules. Do not add to this list.

Definition at line 343 of file cdr.c.

343 {
344 "csv",
345 "custom",
346 "manager",
347 "odbc",
348 "pgsql",
349 "radius",
350 "sqlite",
351 "tds",
352 "mysql",
353 NULL,
354};

◆ ignore_option

struct aco_type ignore_option
static

Definition at line 356 of file cdr.c.

356 {
357 .type = ACO_IGNORE,
358 .name = "modules",
359 .category = (const char*)ignore_categories,
360 .category_match = ACO_WHITELIST_ARRAY,
361};
static const char * ignore_categories[]
Definition cdr.c:343
@ ACO_IGNORE
@ ACO_WHITELIST_ARRAY

◆ mo_list

◆ module_file_conf

struct aco_file module_file_conf
static
Initial value:
= {
.filename = "cdr.conf",
}
static struct aco_type ignore_option
Definition cdr.c:356
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.

The file definition.

Definition at line 368 of file cdr.c.

368 {
369 .filename = "cdr.conf",
371};

◆ parked_state_fn_table

struct cdr_object_fn_table parked_state_fn_table

The virtual table for the Parked state.

Parking is weird. Unlike typical bridges, it has to be treated somewhat uniquely - a channel in a parking bridge (which is a subclass of a holding bridge) has to be handled as if the channel went into an application. However, when the channel comes out, we need a new CDR - unlike the Single state.

Definition at line 782 of file cdr.c.

782 {
783 .name = "Parked",
784 .process_party_a = base_process_party_a,
785 .process_bridge_leave = parked_state_process_bridge_leave,
786 .process_parked_channel = base_process_parked_channel,
787};
static int parked_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition cdr.c:2142

Referenced by dialed_pending_state_process_parking_bridge_enter(), and single_state_process_parking_bridge_enter().

◆ parking_subscription

struct stasis_forward* parking_subscription
static

Our subscription for parking.

Definition at line 484 of file cdr.c.

Referenced by create_subscriptions(), destroy_subscriptions(), and park_and_announce_app_exec().

◆ sched

struct ast_sched_context* sched
static

Scheduler items.

Definition at line 456 of file cdr.c.

◆ single_state_fn_table

struct cdr_object_fn_table single_state_fn_table

The virtual table for the Single state.

A cdr_object starts off in this state. This represents a channel that has no Party B information itself.

A cdr_object from this state can go into any of the following states:

Definition at line 677 of file cdr.c.

677 {
678 .name = "Single",
679 .init_function = single_state_init_function,
680 .process_party_a = base_process_party_a,
681 .process_party_b = single_state_process_party_b,
682 .process_dial_begin = single_state_process_dial_begin,
683 .process_dial_end = base_process_dial_end,
684 .process_bridge_enter = single_state_process_bridge_enter,
685 .process_parking_bridge_enter = single_state_process_parking_bridge_enter,
686 .process_bridge_leave = base_process_bridge_leave,
687 .process_parked_channel = base_process_parked_channel,
688};
static void single_state_init_function(struct cdr_object *cdr)
Definition cdr.c:1743
static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
Definition cdr.c:1710
static void single_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition cdr.c:1749
static int single_state_process_parking_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition cdr.c:1897
static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
Definition cdr.c:1757
static enum process_bridge_enter_results single_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition cdr.c:1840

Referenced by cdr_object_alloc(), dialed_pending_state_process_party_a(), and handle_parking_bridge_enter_message().

◆ stasis_router

struct stasis_message_router* stasis_router
static

Message router for stasis messages regarding channel state.

Definition at line 475 of file cdr.c.

Referenced by ast_cdr_engine_term(), ast_cdr_message_router(), cdr_engine_shutdown(), and load_module().