Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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. More...
 
struct ast_cdrast_cdr_alloc (void)
 Allocate a CDR record. More...
 
int ast_cdr_backend_suspend (const char *name)
 Suspend a CDR backend temporarily. More...
 
int ast_cdr_backend_unsuspend (const char *name)
 Unsuspend a CDR backend. More...
 
int ast_cdr_clear_property (const char *channel_name, enum ast_cdr_options option)
 Clear a property on a CDR for a channel. More...
 
const char * ast_cdr_disp2str (int disposition)
 Disposition to a string. More...
 
struct ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a public CDR. More...
 
void ast_cdr_engine_term (void)
 
int ast_cdr_fork (const char *channel_name, struct ast_flags *options)
 Fork a CDR. More...
 
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. More...
 
void ast_cdr_free (struct ast_cdr *cdr)
 Free a CDR record. More...
 
static int ast_cdr_generic_unregister (struct be_list *generic_list, const char *name)
 
struct ast_cdr_configast_cdr_get_config (void)
 Obtain the current CDR configuration. More...
 
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. More...
 
int ast_cdr_is_enabled (void)
 Return TRUE if CDR subsystem is enabled. More...
 
struct stasis_message_routerast_cdr_message_router (void)
 Return the message router for the CDR engine. More...
 
int ast_cdr_modifier_register (const char *name, const char *desc, ast_cdrbe be)
 Register a CDR modifier. More...
 
int ast_cdr_modifier_unregister (const char *name)
 Unregister a CDR modifier. More...
 
int ast_cdr_register (const char *name, const char *desc, ast_cdrbe be)
 Register a CDR handling engine. More...
 
int ast_cdr_reset (const char *channel_name, int keep_variables)
 Reset the detail record. More...
 
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. More...
 
void ast_cdr_set_config (struct ast_cdr_config *config)
 Set the current CDR configuration. More...
 
int ast_cdr_set_property (const char *channel_name, enum ast_cdr_options option)
 Set a property on a CDR for a channel. More...
 
void ast_cdr_setuserfield (const char *channel_name, const char *userfield)
 Set CDR user field for channel (stored in CDR) More...
 
int ast_cdr_setvar (const char *channel_name, const char *name, const char *value)
 Set a variable on a CDR. More...
 
int ast_cdr_unregister (const char *name)
 Unregister a CDR handling engine. More...
 
struct ast_moduleAST_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. More...
 
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_objectcdr_object_alloc (struct ast_channel_snapshot *chan, const struct timeval *event_time)
 cdr_object constructor More...
 
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. More...
 
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. More...
 
static struct cdr_objectcdr_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. More...
 
static struct ast_cdrcdr_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. More...
 
static void cdr_object_dispatch (struct cdr_object *cdr)
 Dispatch a CDR. More...
 
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. More...
 
static void cdr_object_dtor (void *obj)
 cdr_object Destructor More...
 
static void cdr_object_finalize (struct cdr_object *cdr)
 Finalize a CDR. More...
 
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. More...
 
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. More...
 
static long cdr_object_get_billsec (struct cdr_object *cdr)
 Compute the billsec for a cdr_object. More...
 
static struct cdr_objectcdr_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. More...
 
static struct cdr_object_snapshotcdr_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. More...
 
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. More...
 
static void cdr_object_snapshot_copy (struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src)
 Copy a snapshot and its details. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
static char * cli_complete_show (struct ast_cli_args *a)
 Complete user input for 'cdr show'. More...
 
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. More...
 
static int create_subscriptions (void)
 Create the Stasis subscriptions for CDRs. More...
 
static void destroy_subscriptions (void)
 Destroy the active Stasis subscriptions. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
static void handle_cdr_sync_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for a synchronization message. More...
 
static void handle_channel_snapshot_update_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for channel snapshot update messages. More...
 
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. More...
 
static void handle_parked_call_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for when a channel is parked. More...
 
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. More...
 
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. More...
 
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. More...
 
static void module_config_destructor (void *obj)
 Dispose of a module config object. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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_containeractive_cdrs_all
 A container of all active CDRs with a Party B indexed by Party B channel name. More...
 
static struct ao2_containeractive_cdrs_master
 A container of the active master CDRs indexed by Party A channel uniqueid. More...
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct cdr_batchbatch = NULL
 
static struct be_list be_list = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
struct cdr_object_fn_table bridge_state_fn_table
 The virtual table for the Bridged state. More...
 
static struct stasis_forwardbridge_subscription
 Our subscription for bridges. More...
 
static ast_mutex_t cdr_batch_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 Lock protecting modifications to the batch queue. More...
 
static int cdr_debug_enabled
 
static ast_cond_t cdr_pending_cond
 
static ast_mutex_t cdr_pending_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 These are used to wake up the CDR thread when there's work to do. More...
 
static const char *const cdr_readonly_vars []
 
static int cdr_sched = -1
 
static ast_mutex_t cdr_sched_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 
static pthread_t cdr_thread = AST_PTHREADT_NULL
 
static struct stasis_topiccdr_topic
 The parent topic for all topics we want to aggregate for CDRs. More...
 
static struct stasis_forwardchannel_subscription
 Our subscription for channels. More...
 
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. More...
 
struct cdr_object_fn_table dialed_pending_state_fn_table
 The virtual table for the Dialed Pending state. More...
 
struct cdr_object_fn_table finalized_state_fn_table
 The virtual table for the finalized state. More...
 
static struct aco_type general_option
 The type definition for general options. More...
 
static struct aco_typegeneral_options [] = ACO_TYPES(&general_option)
 
static int global_cdr_sequence = 0
 The global sequence counter used for CDRs. More...
 
static const char * ignore_categories []
 
static struct aco_type ignore_option
 
static struct mo_list mo_list = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static struct aco_file module_file_conf
 The file definition. More...
 
struct cdr_object_fn_table parked_state_fn_table
 The virtual table for the Parked state. More...
 
static struct stasis_forwardparking_subscription
 Our subscription for parking. More...
 
static struct ast_sched_contextsched
 Scheduler items. More...
 
struct cdr_object_fn_table single_state_fn_table
 The virtual table for the Single state. More...
 
static struct stasis_message_routerstasis_router
 Message router for stasis messages regarding channel state. More...
 

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:303

Definition at line 306 of file cdr.c.

◆ 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:306
#define ast_test_flag(p, flag)
Definition: utils.h:63

Definition at line 298 of file cdr.c.

◆ DEFAULT_BATCH_SAFE_SHUTDOWN

#define DEFAULT_BATCH_SAFE_SHUTDOWN   "1"

Definition at line 296 of file cdr.c.

◆ DEFAULT_BATCH_SCHEDULER_ONLY

#define DEFAULT_BATCH_SCHEDULER_ONLY   "0"

Definition at line 295 of file cdr.c.

◆ DEFAULT_BATCH_SIZE

#define DEFAULT_BATCH_SIZE   "100"

Definition at line 291 of file cdr.c.

◆ DEFAULT_BATCH_TIME

#define DEFAULT_BATCH_TIME   "300"

Definition at line 293 of file cdr.c.

◆ DEFAULT_BATCHMODE

#define DEFAULT_BATCHMODE   "0"

Definition at line 282 of file cdr.c.

◆ DEFAULT_CHANNEL_ENABLED

#define DEFAULT_CHANNEL_ENABLED   "1"

Definition at line 287 of file cdr.c.

◆ DEFAULT_CONGESTION

#define DEFAULT_CONGESTION   "0"

Definition at line 284 of file cdr.c.

◆ DEFAULT_ENABLED

#define DEFAULT_ENABLED   "1"

Definition at line 281 of file cdr.c.

◆ DEFAULT_END_BEFORE_H_EXTEN

#define DEFAULT_END_BEFORE_H_EXTEN   "1"

Definition at line 285 of file cdr.c.

◆ DEFAULT_IGNORE_DIAL_CHANGES

#define DEFAULT_IGNORE_DIAL_CHANGES   "0"

Definition at line 289 of file cdr.c.

◆ DEFAULT_IGNORE_STATE_CHANGES

#define DEFAULT_IGNORE_STATE_CHANGES   "0"

Definition at line 288 of file cdr.c.

◆ DEFAULT_INITIATED_SECONDS

#define DEFAULT_INITIATED_SECONDS   "0"

Definition at line 286 of file cdr.c.

◆ DEFAULT_UNANSWERED

#define DEFAULT_UNANSWERED   "0"

Definition at line 283 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 292 of file cdr.c.

◆ MAX_BATCH_TIME

#define MAX_BATCH_TIME   86400

Definition at line 294 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 487 of file cdr.c.

487 {
488 /*!
489 * The CDR was the only party in the bridge.
490 */
492 /*!
493 * The CDR was able to obtain a Party B from some other party already in the bridge
494 */
496 /*!
497 * The CDR was not able to obtain a Party B
498 */
500 /*!
501 * This CDR can't handle a bridge enter message and a new CDR needs to be created
502 */
504};
@ BRIDGE_ENTER_ONLY_PARTY
Definition: cdr.c:491
@ BRIDGE_ENTER_NO_PARTY_B
Definition: cdr.c:499
@ BRIDGE_ENTER_NEED_CDR
Definition: cdr.c:503
@ BRIDGE_ENTER_OBTAINED_PARTY_B
Definition: cdr.c:495

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 4810 of file cdr.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 4810 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 3555 of file cdr.c.

3556{
3557 struct ast_cdr *x;
3558
3559 x = ast_calloc(1, sizeof(*x));
3560 return x;
3561}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
Responsible for call detail data.
Definition: cdr.h:279

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 2986 of file cdr.c.

2987{
2988 int success = -1;
2989 struct cdr_beitem *i = NULL;
2990
2992 AST_RWLIST_TRAVERSE(&be_list, i, list) {
2993 if (!strcasecmp(name, i->name)) {
2994 ast_debug(3, "Suspending CDR backend %s\n", i->name);
2995 i->suspended = 1;
2996 success = 0;
2997 }
2998 }
3000
3001 return success;
3002}
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.
Definition: linkedlists.h:151
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define NULL
Definition: resample.c:96
List of registered backends.
Definition: cdr.c:426
Registration object for CDR backends.
Definition: cdr.c:417
char name[20]
Definition: cdr.c:418

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

Referenced by 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 3004 of file cdr.c.

3005{
3006 int success = -1;
3007 struct cdr_beitem *i = NULL;
3008
3010 AST_RWLIST_TRAVERSE(&be_list, i, list) {
3011 if (!strcasecmp(name, i->name)) {
3012 ast_debug(3, "Unsuspending CDR backend %s\n", i->name);
3013 i->suspended = 0;
3014 success = 0;
3015 }
3016 }
3018
3019 return success;
3020}

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

Referenced by 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 3708 of file cdr.c.

3709{
3710 struct cdr_object *cdr;
3711 struct cdr_object *it_cdr;
3712
3713 cdr = cdr_object_get_by_name(channel_name);
3714 if (!cdr) {
3715 return -1;
3716 }
3717
3718 ao2_lock(cdr);
3719 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3720 if (it_cdr->fn_table == &finalized_state_fn_table) {
3721 continue;
3722 }
3723 ast_clear_flag(&it_cdr->flags, option);
3724 }
3725 ao2_unlock(cdr);
3726
3727 ao2_cleanup(cdr);
3728 return 0;
3729}
#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:790
static struct cdr_object * cdr_object_get_by_name(const char *name)
Definition: cdr.c:3445
An in-memory representation of an active CDR.
Definition: cdr.c:808
struct cdr_object_fn_table * fn_table
Definition: cdr.c:811
struct cdr_object * next
Definition: cdr.c:832
struct ast_flags flags
Definition: cdr.c:819
#define ast_clear_flag(p, flag)
Definition: utils.h:77

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

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 3563 of file cdr.c.

3564{
3565 switch (disposition) {
3566 case AST_CDR_NULL:
3567 return "NO ANSWER"; /* by default, for backward compatibility */
3568 case AST_CDR_NOANSWER:
3569 return "NO ANSWER";
3570 case AST_CDR_FAILED:
3571 return "FAILED";
3572 case AST_CDR_BUSY:
3573 return "BUSY";
3574 case AST_CDR_ANSWERED:
3575 return "ANSWERED";
3576 case AST_CDR_CONGESTION:
3577 return "CONGESTION";
3578 }
3579 return "UNKNOWN";
3580}
@ AST_CDR_CONGESTION
Definition: cdr.h:262
@ AST_CDR_NULL
Definition: cdr.h:258
@ AST_CDR_NOANSWER
Definition: cdr.h:257
@ AST_CDR_ANSWERED
Definition: cdr.h:261
@ AST_CDR_BUSY
Definition: cdr.h:260
@ AST_CDR_FAILED
Definition: cdr.h:259

References AST_CDR_ANSWERED, AST_CDR_BUSY, 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(), 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 3118 of file cdr.c.

3119{
3120 struct ast_cdr *newcdr;
3121
3122 if (!cdr) {
3123 return NULL;
3124 }
3125 newcdr = ast_cdr_alloc();
3126 if (!newcdr) {
3127 return NULL;
3128 }
3129
3130 *newcdr = *cdr;
3132 copy_variables(&newcdr->varshead, &cdr->varshead);
3133 newcdr->next = NULL;
3134
3135 return newcdr;
3136}
struct ast_cdr * ast_cdr_alloc(void)
Allocate a CDR record.
Definition: cdr.c:3555
static int copy_variables(struct varshead *to_list, struct varshead *from_list)
Copy variables from one list to another.
Definition: cdr.c:843
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
struct ast_cdr * next
Definition: cdr.h:332
struct varshead varshead
Definition: cdr.h:330

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

Referenced by custom_log(), manager_log(), and write_cdr().

◆ ast_cdr_engine_term()

void ast_cdr_engine_term ( void  )

Submit any remaining CDRs and prepare for shutdown

Definition at line 4736 of file cdr.c.

4737{
4738 RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
4739
4740 /* Since this is called explicitly during process shutdown, we might not have ever
4741 * been initialized. If so, the config object will be NULL.
4742 */
4743 if (!mod_cfg) {
4744 return;
4745 }
4746
4747 if (cdr_sync_message_type()) {
4748 void *payload;
4749 struct stasis_message *message;
4750
4751 if (!stasis_router) {
4752 return;
4753 }
4754
4755 /* Make sure we have the needed items */
4756 payload = ao2_alloc(sizeof(*payload), NULL);
4757 if (!payload) {
4758 return;
4759 }
4760
4761 ast_debug(1, "CDR Engine termination request received; waiting on messages...\n");
4762
4763 message = stasis_message_create(cdr_sync_message_type(), payload);
4764 if (message) {
4766 }
4768 ao2_cleanup(payload);
4769 }
4770
4771 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4772 cdr_submit_batch(ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN));
4773 }
4774}
#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:467
static void cdr_submit_batch(int shutdown)
Definition: cdr.c:3899
@ CDR_BATCHMODE
Definition: cdr.h:221
@ BATCH_MODE_SAFE_SHUTDOWN
Definition: cdr.h:235
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:318
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

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 3770 of file cdr.c.

3771{
3772 RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
3773 struct cdr_object *new_cdr;
3774 struct cdr_object *it_cdr;
3775 struct cdr_object *cdr_obj;
3776
3777 if (!cdr) {
3778 return -1;
3779 }
3780
3781 {
3782 SCOPED_AO2LOCK(lock, cdr);
3783 struct timeval now = ast_tvnow();
3784
3785 cdr_obj = cdr->last;
3786 if (cdr_obj->fn_table == &finalized_state_fn_table) {
3787 /* If the last CDR in the chain is finalized, don't allow a fork -
3788 * things are already dying at this point
3789 */
3790 return -1;
3791 }
3792
3793 /* Copy over the basic CDR information. The Party A information is
3794 * copied over automatically as part of the append
3795 */
3796 ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
3797 new_cdr = cdr_object_create_and_append(cdr, &now);
3798 if (!new_cdr) {
3799 return -1;
3800 }
3801 new_cdr->fn_table = cdr_obj->fn_table;
3802 ast_string_field_set(new_cdr, bridge, cdr->bridge);
3803 ast_string_field_set(new_cdr, appl, cdr->appl);
3804 ast_string_field_set(new_cdr, data, cdr->data);
3805 ast_string_field_set(new_cdr, context, cdr->context);
3806 ast_string_field_set(new_cdr, exten, cdr->exten);
3807 new_cdr->flags = cdr->flags;
3808 /* Explicitly clear the AST_CDR_LOCK_APP flag - we want
3809 * the application to be changed on the new CDR if the
3810 * dialplan demands it
3811 */
3813
3814 /* If there's a Party B, copy it over as well */
3815 if (cdr_obj->party_b.snapshot) {
3816 new_cdr->party_b.snapshot = cdr_obj->party_b.snapshot;
3817 ao2_ref(new_cdr->party_b.snapshot, +1);
3818 cdr_all_relink(new_cdr);
3819 strcpy(new_cdr->party_b.userfield, cdr_obj->party_b.userfield);
3820 new_cdr->party_b.flags = cdr_obj->party_b.flags;
3822 copy_variables(&new_cdr->party_b.variables, &cdr_obj->party_b.variables);
3823 }
3824 }
3825 new_cdr->start = cdr_obj->start;
3826 new_cdr->answer = cdr_obj->answer;
3827 new_cdr->lastevent = ast_tvnow();
3828
3829 /* Modify the times based on the flags passed in */
3831 && new_cdr->party_a.snapshot->state == AST_STATE_UP) {
3832 new_cdr->answer = ast_tvnow();
3833 }
3835 new_cdr->answer = ast_tvnow();
3836 new_cdr->start = ast_tvnow();
3837 }
3838
3839 /* Create and append, by default, copies over the variables */
3841 free_variables(&new_cdr->party_a.variables);
3842 }
3843
3844 /* Finalize any current CDRs */
3846 for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->next) {
3847 if (it_cdr->fn_table == &finalized_state_fn_table) {
3848 continue;
3849 }
3850 /* Force finalization on the CDR. This will bypass any checks for
3851 * end before 'h' extension.
3852 */
3853 cdr_object_finalize(it_cdr);
3855 }
3856 }
3857 }
3858
3859 return 0;
3860}
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:1172
static void cdr_object_finalize(struct cdr_object *cdr)
Finalize a CDR.
Definition: cdr.c:1537
static void cdr_all_relink(struct cdr_object *cdr)
Definition: cdr.c:1045
static void free_variables(struct varshead *headp)
Delete all variables from a variable list.
Definition: cdr.c:874
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:919
@ AST_CDR_LOCK_APP
Definition: cdr.h:250
@ AST_CDR_FLAG_FINALIZE
Definition: cdr.h:247
@ AST_CDR_FLAG_KEEP_VARS
Definition: cdr.h:243
@ AST_CDR_FLAG_RESET
Definition: cdr.h:249
@ AST_CDR_FLAG_SET_ANSWER
Definition: cdr.h:248
@ AST_STATE_UP
Definition: channelstate.h:42
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:608
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
enum ast_channel_state state
unsigned int flags
Definition: utils.h:200
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.c:802
struct varshead variables
Definition: cdr.c:804
struct ast_channel_snapshot * snapshot
Definition: cdr.c:801
unsigned int flags
Definition: cdr.c:803
struct timeval answer
Definition: cdr.c:815
struct cdr_object_snapshot party_a
Definition: cdr.c:809
struct timeval lastevent
Definition: cdr.c:817
struct cdr_object * last
Definition: cdr.c:833
struct timeval start
Definition: cdr.c:814
struct cdr_object_snapshot party_b
Definition: cdr.c:810
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(), voicemailpwcheck::context, 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(), 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 3170 of file cdr.c.

3171{
3172 const char *fmt = "%Y-%m-%d %T";
3173 const char *varbuf;
3174
3175 if (!cdr) {
3176 return;
3177 }
3178
3179 *ret = NULL;
3180
3181 if (!strcasecmp(name, "clid")) {
3182 ast_copy_string(workspace, cdr->clid, workspacelen);
3183 } else if (!strcasecmp(name, "src")) {
3184 ast_copy_string(workspace, cdr->src, workspacelen);
3185 } else if (!strcasecmp(name, "dst")) {
3186 ast_copy_string(workspace, cdr->dst, workspacelen);
3187 } else if (!strcasecmp(name, "dcontext")) {
3188 ast_copy_string(workspace, cdr->dcontext, workspacelen);
3189 } else if (!strcasecmp(name, "channel")) {
3190 ast_copy_string(workspace, cdr->channel, workspacelen);
3191 } else if (!strcasecmp(name, "dstchannel")) {
3192 ast_copy_string(workspace, cdr->dstchannel, workspacelen);
3193 } else if (!strcasecmp(name, "lastapp")) {
3194 ast_copy_string(workspace, cdr->lastapp, workspacelen);
3195 } else if (!strcasecmp(name, "lastdata")) {
3196 ast_copy_string(workspace, cdr->lastdata, workspacelen);
3197 } else if (!strcasecmp(name, "start")) {
3198 cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
3199 } else if (!strcasecmp(name, "answer")) {
3200 cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
3201 } else if (!strcasecmp(name, "end")) {
3202 cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
3203 } else if (!strcasecmp(name, "duration")) {
3204 snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
3205 } else if (!strcasecmp(name, "billsec")) {
3206 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);
3207 } else if (!strcasecmp(name, "disposition")) {
3208 if (raw) {
3209 snprintf(workspace, workspacelen, "%ld", cdr->disposition);
3210 } else {
3211 ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
3212 }
3213 } else if (!strcasecmp(name, "amaflags")) {
3214 if (raw) {
3215 snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
3216 } else {
3217 ast_copy_string(workspace, ast_channel_amaflags2string(cdr->amaflags), workspacelen);
3218 }
3219 } else if (!strcasecmp(name, "accountcode")) {
3220 ast_copy_string(workspace, cdr->accountcode, workspacelen);
3221 } else if (!strcasecmp(name, "peeraccount")) {
3222 ast_copy_string(workspace, cdr->peeraccount, workspacelen);
3223 } else if (!strcasecmp(name, "uniqueid")) {
3224 ast_copy_string(workspace, cdr->uniqueid, workspacelen);
3225 } else if (!strcasecmp(name, "linkedid")) {
3226 ast_copy_string(workspace, cdr->linkedid, workspacelen);
3227 } else if (!strcasecmp(name, "tenantid")) {
3228 ast_copy_string(workspace, cdr->tenantid, workspacelen);
3229 } else if (!strcasecmp(name, "peertenantid")) {
3230 ast_copy_string(workspace, cdr->peertenantid, workspacelen);
3231 } else if (!strcasecmp(name, "userfield")) {
3232 ast_copy_string(workspace, cdr->userfield, workspacelen);
3233 } else if (!strcasecmp(name, "sequence")) {
3234 snprintf(workspace, workspacelen, "%d", cdr->sequence);
3235 } else if ((varbuf = cdr_format_var_internal(cdr, name))) {
3236 ast_copy_string(workspace, varbuf, workspacelen);
3237 } else {
3238 workspace[0] = '\0';
3239 }
3240
3241 if (!ast_strlen_zero(workspace)) {
3242 *ret = workspace;
3243 }
3244}
static void cdr_get_tv(struct timeval when, const char *fmt, char *buf, int bufsize)
Definition: cdr.c:3155
static const char * cdr_format_var_internal(struct ast_cdr *cdr, const char *name)
Definition: cdr.c:3138
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3563
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4390
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:291
long int disposition
Definition: cdr.h:307
char lastdata[AST_MAX_EXTENSION]
Definition: cdr.h:295
char linkedid[AST_MAX_UNIQUEID]
Definition: cdr.h:319
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.h:325
char peertenantid[AST_MAX_TENANT_ID]
Definition: cdr.h:323
long int billsec
Definition: cdr.h:305
struct timeval answer
Definition: cdr.h:299
char channel[AST_MAX_EXTENSION]
Definition: cdr.h:289
char peeraccount[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:313
long int duration
Definition: cdr.h:303
long int amaflags
Definition: cdr.h:309
char src[AST_MAX_EXTENSION]
Definition: cdr.h:283
char dst[AST_MAX_EXTENSION]
Definition: cdr.h:285
char clid[AST_MAX_EXTENSION]
Definition: cdr.h:281
char uniqueid[AST_MAX_UNIQUEID]
Definition: cdr.h:317
char tenantid[AST_MAX_TENANT_ID]
Definition: cdr.h:321
int sequence
Definition: cdr.h:327
struct timeval start
Definition: cdr.h:297
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:311
char lastapp[AST_MAX_EXTENSION]
Definition: cdr.h:293
char dcontext[AST_MAX_EXTENSION]
Definition: cdr.h:287
struct timeval end
Definition: cdr.h:301
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 3544 of file cdr.c.

3545{
3546 while (cdr) {
3547 struct ast_cdr *next = cdr->next;
3548
3549 free_variables(&cdr->varshead);
3550 ast_free(cdr);
3551 cdr = next;
3552 }
3553}
#define ast_free(a)
Definition: astmm.h:180

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 3073 of file cdr.c.

3074{
3075 struct cdr_beitem *match = NULL;
3076 int active_count;
3077
3078 AST_RWLIST_WRLOCK(generic_list);
3079 AST_RWLIST_TRAVERSE(generic_list, match, list) {
3080 if (!strcasecmp(name, match->name)) {
3081 break;
3082 }
3083 }
3084
3085 if (!match) {
3086 AST_RWLIST_UNLOCK(generic_list);
3087 return 0;
3088 }
3089
3091
3092 if (!match->suspended && active_count != 0) {
3093 AST_RWLIST_UNLOCK(generic_list);
3094 ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
3095 name, active_count);
3096 return -1;
3097 }
3098
3099 AST_RWLIST_REMOVE(generic_list, match, list);
3100 AST_RWLIST_UNLOCK(generic_list);
3101
3102 ast_verb(5, "Unregistered '%s' CDR backend\n", name);
3103 ast_free(match);
3104
3105 return 0;
3106}
#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:461
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:2387
#define AST_LOG_WARNING
#define ast_verb(level,...)
#define AST_RWLIST_REMOVE
Definition: linkedlists.h:885

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, 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 2946 of file cdr.c.

2947{
2948 struct ast_cdr_config *general;
2949 struct module_config *mod_cfg;
2950
2951 mod_cfg = ao2_global_obj_ref(module_configs);
2952 if (!mod_cfg) {
2953 return NULL;
2954 }
2955 general = ao2_bump(mod_cfg->general);
2956 ao2_cleanup(mod_cfg);
2957 return general;
2958}
#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:267
struct ast_cdr_config * general
Definition: cdr.c:319

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 3457 of file cdr.c.

3458{
3459 struct cdr_object *cdr;
3460 struct cdr_object *cdr_obj;
3461
3462 if (ast_strlen_zero(name)) {
3463 return 1;
3464 }
3465
3466 cdr = cdr_object_get_by_name(channel_name);
3467 if (!cdr) {
3468 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3469 return 1;
3470 }
3471
3472 ao2_lock(cdr);
3473
3474 cdr_obj = cdr->last;
3475 if (cdr_object_format_property(cdr_obj, name, value, length)) {
3476 /* Property failed; attempt variable */
3477 cdr_object_format_var_internal(cdr_obj, name, value, length);
3478 }
3479
3480 ao2_unlock(cdr);
3481
3482 ao2_cleanup(cdr);
3483 return 0;
3484}
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:3368
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:3351
#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, and value.

Referenced by 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 2981 of file cdr.c.

2982{
2984}
static int is_cdr_flag_set(unsigned int cdr_flag)
Definition: cdr.c:1222
@ 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 4427 of file cdr.c.

4428{
4429 if (!stasis_router) {
4430 return NULL;
4431 }
4432
4434 return stasis_router;
4435}

References ao2_bump, NULL, and stasis_router.

Referenced by cdr_prop_write(), cdr_read(), cdr_write(), forkcdr_exec(), load_module(), publish_app_cdr_message(), 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 3068 of file cdr.c.

3069{
3070 return cdr_generic_register((struct be_list *)&mo_list, name, desc, be);
3071}
static int cdr_generic_register(struct be_list *generic_list, const char *name, const char *desc, ast_cdrbe be)
Definition: cdr.c:3022
static const char desc[]
Definition: cdr_radius.c:84
char * be
Definition: eagi_proxy.c:73
List of registered modifiers.
Definition: cdr.c:429

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 3113 of file cdr.c.

3114{
3115 return ast_cdr_generic_unregister((struct be_list *)&mo_list, name);
3116}
static int ast_cdr_generic_unregister(struct be_list *generic_list, const char *name)
Definition: cdr.c:3073

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 3063 of file cdr.c.

3064{
3066}

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

Referenced by load_module(), odbc_load_module(), 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 3731 of file cdr.c.

3732{
3733 struct cdr_object *cdr;
3734 struct ast_var_t *vardata;
3735 struct cdr_object *it_cdr;
3736
3737 cdr = cdr_object_get_by_name(channel_name);
3738 if (!cdr) {
3739 return -1;
3740 }
3741
3742 ao2_lock(cdr);
3743 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3744 /* clear variables */
3745 if (!keep_variables) {
3746 while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_a.variables, entries))) {
3747 ast_var_delete(vardata);
3748 }
3749 if (cdr->party_b.snapshot) {
3750 while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_b.variables, entries))) {
3751 ast_var_delete(vardata);
3752 }
3753 }
3754 }
3755
3756 /* Reset to initial state */
3757 memset(&it_cdr->start, 0, sizeof(it_cdr->start));
3758 memset(&it_cdr->end, 0, sizeof(it_cdr->end));
3759 memset(&it_cdr->answer, 0, sizeof(it_cdr->answer));
3760 it_cdr->start = ast_tvnow();
3761 it_cdr->lastevent = it_cdr->start;
3763 }
3764 ao2_unlock(cdr);
3765
3766 ao2_cleanup(cdr);
3767 return 0;
3768}
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:1591
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2471
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
struct timeval end
Definition: cdr.c:816

References cdr_object::answer, 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::end, cdr_object::lastevent, 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 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 3486 of file cdr.c.

3487{
3488 struct cdr_object *cdr;
3489 struct cdr_object *it_cdr;
3490 struct ast_var_t *variable;
3491 const char *var;
3492 char workspace[256];
3493 int total = 0, x = 0, i;
3494
3495 cdr = cdr_object_get_by_name(channel_name);
3496 if (!cdr) {
3498 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3499 }
3500 return 0;
3501 }
3502
3504
3505 ao2_lock(cdr);
3506 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3507 if (++x > 1) {
3508 ast_str_append(buf, 0, "\n");
3509 }
3510
3511 AST_LIST_TRAVERSE(&it_cdr->party_a.variables, variable, entries) {
3512 if (!(var = ast_var_name(variable))) {
3513 continue;
3514 }
3515
3516 if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variable), ""), sep) < 0) {
3517 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3518 break;
3519 }
3520
3521 total++;
3522 }
3523
3524 for (i = 0; cdr_readonly_vars[i]; i++) {
3525 if (cdr_object_format_property(it_cdr, cdr_readonly_vars[i], workspace, sizeof(workspace))) {
3526 /* Unhandled read-only CDR variable. */
3527 ast_assert(0);
3528 continue;
3529 }
3530
3531 if (!ast_strlen_zero(workspace)
3532 && ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, workspace, sep) < 0) {
3533 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3534 break;
3535 }
3536 total++;
3537 }
3538 }
3539 ao2_unlock(cdr);
3540 ao2_cleanup(cdr);
3541 return total;
3542}
#define var
Definition: ast_expr2f.c:605
static const char *const cdr_readonly_vars[]
Definition: cdr.c:3278
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.
Definition: linkedlists.h:491
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::@213 entries
#define ast_assert(a)
Definition: utils.h:739

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, 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 2960 of file cdr.c.

2961{
2962 struct module_config *mod_cfg;
2963
2964 if (!config) {
2965 return;
2966 }
2967
2968 mod_cfg = ao2_global_obj_ref(module_configs);
2969 if (!mod_cfg) {
2970 return;
2971 }
2972
2973 ao2_replace(mod_cfg->general, config);
2974
2975 cdr_set_debug_mode(mod_cfg);
2977
2978 ao2_cleanup(mod_cfg);
2979}
#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:298
static int cdr_toggle_runtime_options(void)
Checks if CDRs are enabled and enables/disables the necessary options.
Definition: cdr.c:4623
static const char config[]
Definition: chan_ooh323.c:111

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 3681 of file cdr.c.

3682{
3683 struct cdr_object *cdr;
3684 struct cdr_object *it_cdr;
3685
3686 cdr = cdr_object_get_by_name(channel_name);
3687 if (!cdr) {
3688 return -1;
3689 }
3690
3691 ao2_lock(cdr);
3692 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3693 if (it_cdr->fn_table == &finalized_state_fn_table) {
3694 continue;
3695 }
3696 /* Note: in general, set the flags on both the CDR record as well as the
3697 * Party A. Sometimes all we have is the Party A to look at.
3698 */
3699 ast_set_flag(&it_cdr->flags, option);
3700 ast_set_flag(&it_cdr->party_a, option);
3701 }
3702 ao2_unlock(cdr);
3703
3704 ao2_cleanup(cdr);
3705 return 0;
3706}
#define ast_set_flag(p, flag)
Definition: utils.h:70

References ao2_cleanup, ao2_lock, ao2_unlock, ast_set_flag, cdr_object_get_by_name(), finalized_state_fn_table, cdr_object::flags, cdr_object::fn_table, cdr_object::next, and cdr_object::party_a.

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 3610 of file cdr.c.

3611{
3612 struct cdr_object *cdr;
3613 struct party_b_userfield_update party_b_info = {
3615 .userfield = userfield,
3616 };
3617 struct cdr_object *it_cdr;
3618
3619 /* Handle Party A */
3620 cdr = cdr_object_get_by_name(channel_name);
3621 if (cdr) {
3622 ao2_lock(cdr);
3623 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3624 if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3625 continue;
3626 }
3627 ast_copy_string(it_cdr->party_a.userfield, userfield,
3628 sizeof(it_cdr->party_a.userfield));
3629 }
3630 ao2_unlock(cdr);
3631 }
3632
3633 /* Handle Party B */
3636 &party_b_info);
3637
3638 ao2_cleanup(cdr);
3639}
#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:3588
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:464
const char * userfield
Definition: cdr.c:3584
const char * channel_name
Definition: cdr.c:3583

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::fn_table, cdr_object::next, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_SEARCH_KEY, cdr_object::party_a, cdr_object_snapshot::userfield, 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 3303 of file cdr.c.

3304{
3305 struct cdr_object *cdr;
3306 struct cdr_object *it_cdr;
3307 struct ao2_iterator *it_cdrs;
3308 char *arg = ast_strdupa(channel_name);
3309 int x;
3310
3311 for (x = 0; cdr_readonly_vars[x]; x++) {
3312 if (!strcasecmp(name, cdr_readonly_vars[x])) {
3313 ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!\n", name);
3314 return -1;
3315 }
3316 }
3317
3319 if (!it_cdrs) {
3320 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3321 return -1;
3322 }
3323
3324 for (; (cdr = ao2_iterator_next(it_cdrs)); ao2_unlock(cdr), ao2_cleanup(cdr)) {
3325 ao2_lock(cdr);
3326 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3327 struct varshead *headp = NULL;
3328
3329 if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3330 continue;
3331 }
3332 if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->base->name)) {
3333 headp = &it_cdr->party_a.variables;
3334 } else if (it_cdr->party_b.snapshot
3335 && !strcasecmp(channel_name, it_cdr->party_b.snapshot->base->name)) {
3336 headp = &it_cdr->party_b.variables;
3337 }
3338 if (headp) {
3339 set_variable(headp, name, value);
3340 }
3341 }
3342 }
3343 ao2_iterator_destroy(it_cdrs);
3344
3345 return 0;
3346}
#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:3250
static void set_variable(struct varshead *headp, const char *name, const char *value)
Definition: cdr.c:1357
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, value, and cdr_object_snapshot::variables.

Referenced by 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 3108 of file cdr.c.

3109{
3111}

References ast_cdr_generic_unregister(), and name.

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

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 4810 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 1708 of file cdr.c.

1709{
1710 /* Base process bridge enter simply indicates that we can't handle it */
1711 return BRIDGE_ENTER_NEED_CDR;
1712}

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 1698 of file cdr.c.

1699{
1700 return 0;
1701}

◆ 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 1703 of file cdr.c.

1704{
1705 return 0;
1706}

◆ 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 1714 of file cdr.c.

1715{
1716 char park_info[128];
1717
1718 ast_assert(!strcasecmp(parking_info->parkee->base->name, cdr->party_a.snapshot->base->name));
1719
1720 /* Update Party A information regardless */
1721 cdr->fn_table->process_party_a(cdr, parking_info->parkee);
1722
1723 /* Fake out where we're parked */
1724 ast_string_field_set(cdr, appl, "Park");
1725 snprintf(park_info, sizeof(park_info), "%s:%u", parking_info->parkinglot, parking_info->parkingspace);
1726 ast_string_field_set(cdr, data, park_info);
1727
1728 /* Prevent any further changes to the App/Data fields for this record */
1730
1731 return 0;
1732}
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:533

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, ast_parked_call_payload::parkee, ast_parked_call_payload::parkinglot, ast_parked_call_payload::parkingspace, cdr_object::party_a, cdr_object_fn_table::process_party_a, and cdr_object_snapshot::snapshot.

◆ base_process_party_a()

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

Definition at line 1637 of file cdr.c.

1638{
1639 ast_assert(strcasecmp(snapshot->base->name, cdr->party_a.snapshot->base->name) == 0);
1640
1641 /* Finalize the CDR if we're in hangup logic and we're set to do so */
1645 return 0;
1646 }
1647
1648 /*
1649 * Only record the context and extension if we aren't in a subroutine, or if
1650 * we are executing hangup logic.
1651 */
1654 if (strcmp(cdr->context, snapshot->dialplan->context)) {
1655 ast_string_field_set(cdr, context, snapshot->dialplan->context);
1656 }
1657 if (strcmp(cdr->exten, snapshot->dialplan->exten)) {
1658 ast_string_field_set(cdr, exten, snapshot->dialplan->exten);
1659 }
1660 }
1661
1662 cdr_object_swap_snapshot(&cdr->party_a, snapshot);
1663
1664 /* When Party A is originated to an application and the application exits, the stack
1665 * will attempt to clear the application and restore the dummy originate application
1666 * of "AppDialX". Prevent that, and any other application changes we might not want
1667 * here.
1668 */
1670 && !ast_strlen_zero(snapshot->dialplan->appl)
1671 && (strncasecmp(snapshot->dialplan->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
1672 if (strcmp(cdr->appl, snapshot->dialplan->appl)) {
1673 ast_string_field_set(cdr, appl, snapshot->dialplan->appl);
1674 }
1675 if (strcmp(cdr->data, snapshot->dialplan->data)) {
1676 ast_string_field_set(cdr, data, snapshot->dialplan->data);
1677 }
1678
1679 /* Dial (app_dial) is a special case. Because pre-dial handlers, which
1680 * execute before the dial begins, will alter the application/data to
1681 * something people typically don't want to see, if we see a channel enter
1682 * into Dial here, we set the appl/data accordingly and lock it.
1683 */
1684 if (!strcmp(snapshot->dialplan->appl, "Dial")) {
1686 }
1687 }
1688
1689 if (strcmp(cdr->linkedid, snapshot->peer->linkedid)) {
1690 ast_string_field_set(cdr, linkedid, snapshot->peer->linkedid);
1691 }
1694
1695 return 0;
1696}
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:1628
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:1574
@ 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:831
const ast_string_field data
Definition: cdr.c:831
const ast_string_field context
Definition: cdr.c:831
const ast_string_field exten
Definition: cdr.c:831
const ast_string_field appl
Definition: cdr.c:831

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(), voicemailpwcheck::context, 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, and ast_channel_snapshot::softhangup_flags.

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 2593 of file cdr.c.

2595{
2596 struct cdr_object *new_cdr;
2597
2598 new_cdr = cdr_object_create_and_append(cdr, &cdr->lastevent);
2599 if (!new_cdr) {
2600 return;
2601 }
2603 cdr_all_relink(new_cdr);
2605 ast_string_field_set(new_cdr, bridge, cdr->bridge);
2607 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2608 new_cdr, new_cdr->party_a.snapshot->base->name,
2610}
struct cdr_object_fn_table bridge_state_fn_table
The virtual table for the Bridged state.
Definition: cdr.c:755
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:888
const ast_string_field bridge
Definition: cdr.c:831

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_a, cdr_object::party_b, and cdr_object_snapshot::snapshot.

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 2624 of file cdr.c.

2625{
2626 struct cdr_object_snapshot *party_a;
2627 struct cdr_object *cand_cdr;
2628
2629 ao2_lock(base_cand_cdr);
2630
2631 for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->next) {
2632 /* Skip any records that are not in this bridge */
2633 if (strcmp(cand_cdr->bridge, cdr->bridge)) {
2634 continue;
2635 }
2636
2637 /* If the candidate is us or someone we've taken on, pass on by */
2638 if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)
2639 || (cdr->party_b.snapshot
2640 && !strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name))) {
2641 break;
2642 }
2643
2644 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
2645 /* We're party A - make a new CDR, append it to us, and set the candidate as
2646 * Party B */
2647 if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
2648 bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
2649 break;
2650 }
2651
2652 /* We're Party B. Check if we can add ourselves immediately or if we need
2653 * a new CDR for them (they already have a Party B) */
2654 if (cand_cdr->party_b.snapshot
2655 && strcasecmp(cand_cdr->party_b.snapshot->base->name, cdr->party_a.snapshot->base->name)) {
2656 bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a);
2657 } else {
2658 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2659 cand_cdr, cand_cdr->party_a.snapshot->base->name,
2660 cdr->party_a.snapshot->base->name);
2661 cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
2662 cdr_all_relink(cand_cdr);
2663 /* It's possible that this joined at one point and was never chosen
2664 * as party A. Clear their end time, as it would be set in such a
2665 * case.
2666 */
2667 memset(&cand_cdr->end, 0, sizeof(cand_cdr->end));
2668 }
2669
2670 break;
2671 }
2672
2673 ao2_unlock(base_cand_cdr);
2674}
static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, struct cdr_object_snapshot *party_b)
Definition: cdr.c:2593
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:1287
A wrapper object around a snapshot. Fields that are mutable by the CDR engine are replicated here.
Definition: cdr.c:800

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(), cdr_object::end, ast_channel_snapshot_base::name, cdr_object::next, cdr_object::party_a, cdr_object::party_b, and cdr_object_snapshot::snapshot.

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 2112 of file cdr.c.

2113{
2114 if (strcmp(cdr->bridge, bridge->uniqueid)) {
2115 return 1;
2116 }
2117 if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)
2118 && cdr->party_b.snapshot
2119 && strcasecmp(cdr->party_b.snapshot->base->name, channel->base->name)) {
2120 return 1;
2121 }
2123
2124 return 0;
2125}
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, and cdr_object_snapshot::snapshot.

◆ 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 1010 of file cdr.c.

1011{
1012 struct cdr_object *left = obj;
1013 struct cdr_object *right = arg;
1014 const char *right_key = arg;
1015 int cmp;
1016
1017 switch (flags & OBJ_SEARCH_MASK) {
1018 case OBJ_SEARCH_OBJECT:
1019 right_key = right->party_b_name;
1020 /* Fall through */
1021 case OBJ_SEARCH_KEY:
1022 cmp = strcasecmp(left->party_b_name, right_key);
1023 break;
1025 /*
1026 * We could also use a partial key struct containing a length
1027 * so strlen() does not get called for every comparison instead.
1028 */
1029 cmp = strncasecmp(left->party_b_name, right_key, strlen(right_key));
1030 break;
1031 default:
1032 /* Sort can only work on something with a full or partial key. */
1033 ast_assert(0);
1034 cmp = 0;
1035 break;
1036 }
1037 return cmp ? 0 : CMP_MATCH;
1038}
@ 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:831

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

Referenced by load_module().

◆ cdr_all_hash_fn()

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

Definition at line 986 of file cdr.c.

987{
988 const struct cdr_object *cdr;
989 const char *key;
990
991 switch (flags & OBJ_SEARCH_MASK) {
992 case OBJ_SEARCH_KEY:
993 key = obj;
994 break;
996 cdr = obj;
997 key = cdr->party_b_name;
998 break;
999 default:
1000 ast_assert(0);
1001 return 0;
1002 }
1003 return ast_str_case_hash(key);
1004}
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 4607 of file cdr.c.

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

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

Referenced by load_module().

◆ cdr_all_relink()

static void cdr_all_relink ( struct cdr_object cdr)
static

Definition at line 1045 of file cdr.c.

1046{
1048 if (cdr->party_b.snapshot) {
1049 if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->base->name)) {
1051 ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->base->name);
1053 }
1054 } else {
1056 ast_string_field_set(cdr, party_b_name, "");
1057 }
1059}
#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, and cdr_object_snapshot::snapshot.

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 1066 of file cdr.c.

1067{
1068 struct cdr_object *cur;
1069 struct cdr_object *next;
1070
1071 ast_assert(cdr->is_root);
1072
1073 /* Hold a ref to the root CDR to ensure the list members don't go away on us. */
1074 ao2_ref(cdr, +1);
1076 for (cur = cdr; cur; cur = next) {
1077 next = cur->next;
1079 /*
1080 * It is safe to still use cur after unlinking because the
1081 * root CDR holds a ref to all the CDRs in the list and we
1082 * have a ref to the root CDR.
1083 */
1085 }
1087 ao2_ref(cdr, -1);
1088}
int is_root
Definition: cdr.c:834

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 3974 of file cdr.c.

3975{
3976 struct cdr_batch_item *newtail;
3977 int curr;
3978 RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
3979 int submit_batch = 0;
3980
3981 if (!cdr) {
3982 return;
3983 }
3984
3985 /* maybe they disabled CDR stuff completely, so just drop it */
3986 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
3987 ast_debug(1, "Dropping CDR !\n");
3989 return;
3990 }
3991
3992 /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
3993 if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
3994 post_cdr(cdr);
3996 return;
3997 }
3998
3999 /* otherwise, each CDR gets put into a batch list (at the end) */
4000 ast_debug(1, "CDR detaching from this thread\n");
4001
4002 /* we'll need a new tail for every CDR */
4003 if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
4004 post_cdr(cdr);
4006 return;
4007 }
4008
4009 /* don't traverse a whole list (just keep track of the tail) */
4011 if (!batch)
4012 init_batch();
4013 if (!batch->head) {
4014 /* new batch is empty, so point the head at the new tail */
4015 batch->head = newtail;
4016 } else {
4017 /* already got a batch with something in it, so just append a new tail */
4018 batch->tail->next = newtail;
4019 }
4020 newtail->cdr = cdr;
4021 batch->tail = newtail;
4022 curr = batch->size++;
4023
4024 /* if we have enough stuff to post, then do it */
4025 if (curr >= (mod_cfg->general->batch_settings.size - 1)) {
4026 submit_batch = 1;
4027 }
4029
4030 /* Don't submit a batch with cdr_batch_lock held */
4031 if (submit_batch) {
4033 }
4034}
void ast_cdr_free(struct ast_cdr *cdr)
Free a CDR record.
Definition: cdr.c:3544
static ast_mutex_t cdr_batch_lock
Lock protecting modifications to the batch queue.
Definition: cdr.c:454
static struct cdr_batch * batch
static int init_batch(void)
Definition: cdr.c:3871
static void start_batch_mode(void)
Definition: cdr.c:3958
static void post_cdr(struct ast_cdr *cdr)
Definition: cdr.c:3641
#define ast_mutex_unlock(a)
Definition: lock.h:194
#define ast_mutex_lock(a)
Definition: lock.h:193
Queued CDR waiting to be batched.
Definition: cdr.c:432
struct ast_cdr * cdr
Definition: cdr.c:433
struct cdr_batch_item * next
Definition: cdr.c:434
int size
Definition: cdr.c:439
struct cdr_batch_item * head
Definition: cdr.c:440
struct cdr_batch_item * tail
Definition: cdr.c:441

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 4555 of file cdr.c.

4556{
4557 /* Only create the thread level portions once */
4561 ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
4562 return;
4563 }
4564 }
4565
4566 /* Start the batching process */
4568
4569 ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %u or time %u seconds.\n",
4570 config->batch_settings.size, config->batch_settings.time);
4571}
static pthread_t cdr_thread
Definition: cdr.c:451
static ast_cond_t cdr_pending_cond
Definition: cdr.c:458
static void * do_cdr(void *data)
Definition: cdr.c:4036
#define LOG_NOTICE
#define AST_PTHREADT_NULL
Definition: lock.h:70
#define ast_cond_init(cond, attr)
Definition: lock.h:205
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592

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 4524 of file cdr.c.

4525{
4528
4530 cdr_topic = NULL;
4531
4532 STASIS_MESSAGE_TYPE_CLEANUP(cdr_sync_message_type);
4533
4539 sched = NULL;
4540 ast_free(batch);
4541 batch = NULL;
4542
4543 aco_info_destroy(&cfg_info);
4544 ao2_global_obj_release(module_configs);
4545
4546 ao2_container_unregister("cdrs_master");
4549
4550 ao2_container_unregister("cdrs_all");
4553}
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:4396
static struct ast_cli_entry cli_commands[]
Definition: cdr.c:4385
static void finalize_batch_mode(void)
Definition: cdr.c:4413
static struct stasis_topic * cdr_topic
The parent topic for all topics we want to aggregate for CDRs.
Definition: cdr.c:479
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
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:1515
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:666

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 3138 of file cdr.c.

3139{
3140 struct ast_var_t *variables;
3141
3142 if (ast_strlen_zero(name)) {
3143 return NULL;
3144 }
3145
3146 AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
3147 if (!strcasecmp(name, ast_var_name(variables))) {
3148 return ast_var_value(variables);
3149 }
3150 }
3151
3152 return NULL;
3153}

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 3022 of file cdr.c.

3023{
3024 struct cdr_beitem *i;
3025 struct cdr_beitem *cur;
3026
3027 if (!name) {
3028 return -1;
3029 }
3030
3031 if (!be) {
3032 ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
3033
3034 return -1;
3035 }
3036
3037 i = ast_calloc(1, sizeof(*i));
3038 if (!i) {
3039 return -1;
3040 }
3041
3042 i->be = be;
3043 ast_copy_string(i->name, name, sizeof(i->name));
3044 ast_copy_string(i->desc, desc, sizeof(i->desc));
3045
3046 AST_RWLIST_WRLOCK(generic_list);
3047 AST_RWLIST_TRAVERSE(generic_list, cur, list) {
3048 if (!strcasecmp(name, cur->name)) {
3049 ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
3050 AST_RWLIST_UNLOCK(generic_list);
3051 ast_free(i);
3052
3053 return -1;
3054 }
3055 }
3056
3057 AST_RWLIST_INSERT_HEAD(generic_list, i, list);
3058 AST_RWLIST_UNLOCK(generic_list);
3059
3060 return 0;
3061}
#define LOG_WARNING
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
ast_cdrbe be
Definition: cdr.c:420
char desc[80]
Definition: cdr.c:419

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, 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 3155 of file cdr.c.

3156{
3157 if (fmt == NULL) { /* raw mode */
3158 snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
3159 } else {
3160 buf[0] = '\0';/* Ensure the buffer is initialized. */
3161 if (when.tv_sec) {
3162 struct ast_tm tm;
3163
3164 ast_localtime(&when, &tm, NULL);
3165 ast_strftime(buf, bufsize, fmt, &tm);
3166 }
3167 }
3168}
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 952 of file cdr.c.

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

References ast_assert, CMP_MATCH, cdr_object::flags, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, OBJ_SEARCH_PARTIAL_KEY, 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 928 of file cdr.c.

929{
930 const struct cdr_object *cdr;
931 const char *key;
932
933 switch (flags & OBJ_SEARCH_MASK) {
934 case OBJ_SEARCH_KEY:
935 key = obj;
936 break;
938 cdr = obj;
939 key = cdr->uniqueid;
940 break;
941 default:
942 ast_assert(0);
943 return 0;
944 }
945 return ast_str_case_hash(key);
946}

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 4582 of file cdr.c.

4583{
4584 struct cdr_object *cdr = v_obj;
4585 struct cdr_object *it_cdr;
4586
4587 if (!cdr) {
4588 return;
4589 }
4590 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4591 prnt(where, "Party A: %s; Party B: %s; Bridge %s\n",
4592 it_cdr->party_a.snapshot->base->name,
4593 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<unknown>",
4594 it_cdr->bridge);
4595 }
4596}

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

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 1134 of file cdr.c.

1135{
1136 struct cdr_object *cdr;
1137
1138 ast_assert(chan != NULL);
1139
1140 cdr = ao2_alloc(sizeof(*cdr), cdr_object_dtor);
1141 if (!cdr) {
1142 return NULL;
1143 }
1144 cdr->last = cdr;
1145 if (ast_string_field_init(cdr, 64)) {
1146 ao2_cleanup(cdr);
1147 return NULL;
1148 }
1150 ast_string_field_set(cdr, name, chan->base->name);
1155 cdr->lastevent = *event_time;
1156
1157 cdr->party_a.snapshot = chan;
1158 ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
1159
1160 CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->base->name);
1161
1163
1164 return cdr;
1165}
#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:669
static int global_cdr_sequence
The global sequence counter used for CDRs.
Definition: cdr.c:445
static void cdr_object_dtor(void *obj)
cdr_object Destructor
Definition: cdr.c:1093
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:761
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
const ast_string_field tenantid
const ast_string_field uniqueid
unsigned int sequence
Definition: cdr.c:818
const ast_string_field tenantid
Definition: cdr.c:831
enum ast_cdr_disposition disposition
Definition: cdr.c:813

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::tenantid, cdr_object::tenantid, 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 1591 of file cdr.c.

1592{
1593 if (cdr->party_a.snapshot->state == AST_STATE_UP && ast_tvzero(cdr->answer)) {
1594 cdr->answer = cdr->lastevent;
1595 /* tv_usec is suseconds_t, which could be int or long */
1596 CDR_DEBUG("%p - Set answered time to %ld.%06ld\n", cdr,
1597 (long)cdr->answer.tv_sec,
1598 (long)cdr->answer.tv_usec);
1599 }
1600}

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 1172 of file cdr.c.

1173{
1174 struct cdr_object *new_cdr;
1175 struct cdr_object *it_cdr;
1176 struct cdr_object *cdr_last;
1177
1178 cdr_last = cdr->last;
1179 new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot, event_time);
1180 if (!new_cdr) {
1181 return NULL;
1182 }
1183 new_cdr->disposition = AST_CDR_NULL;
1184
1185 /* Copy over the linkedid, as it may have changed */
1186 ast_string_field_set(new_cdr, linkedid, cdr_last->linkedid);
1187 ast_string_field_set(new_cdr, appl, cdr_last->appl);
1188 ast_string_field_set(new_cdr, data, cdr_last->data);
1189 ast_string_field_set(new_cdr, context, cdr_last->context);
1190 ast_string_field_set(new_cdr, exten, cdr_last->exten);
1191
1192 /*
1193 * If the current CDR says to disable all future ones,
1194 * keep the disable chain going
1195 */
1196 if (ast_test_flag(&cdr_last->flags, AST_CDR_FLAG_DISABLE_ALL)) {
1198 }
1199
1200 /* Copy over other Party A information */
1201 cdr_object_snapshot_copy(&new_cdr->party_a, &cdr_last->party_a);
1202
1203 /* Append the CDR to the end of the list */
1204 for (it_cdr = cdr; it_cdr->next; it_cdr = it_cdr->next) {
1205 it_cdr->last = new_cdr;
1206 }
1207 it_cdr->last = new_cdr;
1208 it_cdr->next = new_cdr;
1209
1210 return new_cdr;
1211}
static struct cdr_object * cdr_object_alloc(struct ast_channel_snapshot *chan, const struct timeval *event_time)
cdr_object constructor
Definition: cdr.c:1134
@ AST_CDR_FLAG_DISABLE_ALL
Definition: cdr.h:245

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(), voicemailpwcheck::context, cdr_object::context, cdr_object::data, cdr_object::disposition, cdr_object::exten, cdr_object::flags, cdr_object::last, cdr_object::linkedid, cdr_object::next, NULL, cdr_object::party_a, and cdr_object_snapshot::snapshot.

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 1382 of file cdr.c.

1383{
1384 struct ast_cdr *pub_cdr = NULL, *cdr_prev = NULL;
1385 struct cdr_object *it_cdr;
1386 struct ast_var_t *it_var, *it_copy_var;
1387 struct ast_channel_snapshot *party_a;
1388 struct ast_channel_snapshot *party_b;
1389
1390 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
1391 struct ast_cdr *cdr_copy;
1392
1393 /* Don't create records for CDRs where the party A was a dialed channel */
1394 if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
1395 ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
1396 it_cdr->party_a.snapshot->base->name);
1397 continue;
1398 }
1399
1400 cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
1401 if (!cdr_copy) {
1402 ast_free(pub_cdr);
1403 return NULL;
1404 }
1405
1406 party_a = it_cdr->party_a.snapshot;
1407 party_b = it_cdr->party_b.snapshot;
1408
1409 /* Party A */
1410 ast_assert(party_a != NULL);
1411 ast_copy_string(cdr_copy->accountcode, party_a->base->accountcode, sizeof(cdr_copy->accountcode));
1412 cdr_copy->amaflags = party_a->amaflags;
1413 ast_copy_string(cdr_copy->channel, party_a->base->name, sizeof(cdr_copy->channel));
1414 ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller->name, party_a->caller->number, "");
1415 ast_copy_string(cdr_copy->src, party_a->caller->number, sizeof(cdr_copy->src));
1416 ast_copy_string(cdr_copy->uniqueid, party_a->base->uniqueid, sizeof(cdr_copy->uniqueid));
1417 ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
1418 ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
1419 ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
1420 ast_copy_string(cdr_copy->dcontext, it_cdr->context, sizeof(cdr_copy->dcontext));
1421 ast_copy_string(cdr_copy->tenantid, it_cdr->tenantid, sizeof(cdr_copy->tenantid));
1422
1423 /* Party B */
1424 if (party_b) {
1425 ast_copy_string(cdr_copy->dstchannel, party_b->base->name, sizeof(cdr_copy->dstchannel));
1426 ast_copy_string(cdr_copy->peeraccount, party_b->base->accountcode, sizeof(cdr_copy->peeraccount));
1427 if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
1428 snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
1429 }
1430 ast_copy_string(cdr_copy->peertenantid, party_b->base->tenantid, sizeof(cdr_copy->peertenantid));
1431 }
1432 if (ast_strlen_zero(cdr_copy->userfield) && !ast_strlen_zero(it_cdr->party_a.userfield)) {
1433 ast_copy_string(cdr_copy->userfield, it_cdr->party_a.userfield, sizeof(cdr_copy->userfield));
1434 }
1435
1436 /* Timestamps/durations */
1437 cdr_copy->start = it_cdr->start;
1438 cdr_copy->answer = it_cdr->answer;
1439 cdr_copy->end = it_cdr->end;
1440 cdr_copy->billsec = cdr_object_get_billsec(it_cdr);
1441 cdr_copy->duration = cdr_object_get_duration(it_cdr);
1442
1443 /* Flags and IDs */
1444 ast_copy_flags(cdr_copy, &it_cdr->flags, AST_FLAGS_ALL);
1445 ast_copy_string(cdr_copy->linkedid, it_cdr->linkedid, sizeof(cdr_copy->linkedid));
1446 cdr_copy->disposition = it_cdr->disposition;
1447 cdr_copy->sequence = it_cdr->sequence;
1448
1449 /* Variables */
1450 copy_variables(&cdr_copy->varshead, &it_cdr->party_a.variables);
1451 AST_LIST_TRAVERSE(&it_cdr->party_b.variables, it_var, entries) {
1452 int found = 0;
1453 struct ast_var_t *newvariable;
1454 AST_LIST_TRAVERSE(&cdr_copy->varshead, it_copy_var, entries) {
1455 if (!strcasecmp(ast_var_name(it_var), ast_var_name(it_copy_var))) {
1456 found = 1;
1457 break;
1458 }
1459 }
1460 if (!found && (newvariable = ast_var_assign(ast_var_name(it_var), ast_var_value(it_var)))) {
1461 AST_LIST_INSERT_TAIL(&cdr_copy->varshead, newvariable, entries);
1462 }
1463 }
1464
1465 if (!pub_cdr) {
1466 pub_cdr = cdr_copy;
1467 cdr_prev = pub_cdr;
1468 } else {
1469 cdr_prev->next = cdr_copy;
1470 cdr_prev = cdr_copy;
1471 }
1472 }
1473
1474 return pub_cdr;
1475}
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:1322
static long cdr_object_get_billsec(struct cdr_object *cdr)
Compute the billsec for a cdr_object.
Definition: cdr.c:1330
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:1274
#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.
Definition: linkedlists.h:731
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:84
#define AST_FLAGS_ALL
Definition: utils.h:196

References ast_cdr::accountcode, ast_channel_snapshot_base::accountcode, ast_cdr::amaflags, ast_channel_snapshot::amaflags, ast_cdr::answer, cdr_object::answer, cdr_object::appl, 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_cdr::billsec, ast_channel_snapshot::caller, cdr_object_get_billsec(), cdr_object_get_duration(), ast_cdr::channel, ast_cdr::clid, cdr_object::context, copy_variables(), cdr_object::data, ast_cdr::dcontext, ast_cdr::disposition, cdr_object::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, cdr_object::end, ast_var_t::entries, cdr_object::exten, cdr_object::flags, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::linkedid, cdr_object::linkedid, ast_channel_snapshot_caller::name, ast_channel_snapshot_base::name, ast_cdr::next, cdr_object::next, NULL, ast_channel_snapshot_caller::number, cdr_object::party_a, cdr_object::party_b, ast_cdr::peeraccount, ast_cdr::peertenantid, ast_cdr::sequence, cdr_object::sequence, cdr_object_snapshot::snapshot, snapshot_is_dialed(), ast_cdr::src, ast_cdr::start, cdr_object::start, ast_cdr::tenantid, ast_channel_snapshot_base::tenantid, cdr_object::tenantid, ast_cdr::uniqueid, ast_channel_snapshot_base::uniqueid, ast_cdr::userfield, cdr_object_snapshot::userfield, cdr_object_snapshot::variables, 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 1483 of file cdr.c.

1484{
1485 struct ast_cdr *pub_cdr;
1486
1487 CDR_DEBUG("%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
1488 cdr->party_a.snapshot->base->name,
1489 cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<none>");
1490 pub_cdr = cdr_object_create_public_records(cdr);
1491 cdr_detach(pub_cdr);
1492}
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:1382
static void cdr_detach(struct ast_cdr *cdr)
Definition: cdr.c:3974

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, and cdr_object_snapshot::snapshot.

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 4396 of file cdr.c.

4397{
4398 struct cdr_object *cdr = obj;
4399 struct cdr_object *it_cdr;
4400
4401 ao2_lock(cdr);
4402 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4404 }
4406 ao2_unlock(cdr);
4407
4408 cdr_all_unlink(cdr);
4409
4410 return CMP_MATCH;
4411}
static void cdr_all_unlink(struct cdr_object *cdr)
Definition: cdr.c:1066
static void cdr_object_dispatch(struct cdr_object *cdr)
Dispatch a CDR.
Definition: cdr.c:1483

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

Referenced by cdr_engine_shutdown().

◆ cdr_object_dtor()

static void cdr_object_dtor ( void *  obj)
static

cdr_object Destructor

Definition at line 1093 of file cdr.c.

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

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, 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 1537 of file cdr.c.

1538{
1539 if (!ast_tvzero(cdr->end)) {
1540 return;
1541 }
1542 cdr->end = cdr->lastevent;
1543
1544 if (cdr->disposition == AST_CDR_NULL) {
1545 if (!ast_tvzero(cdr->answer)) {
1547 } else if (cdr->party_a.snapshot->hangup->cause) {
1549 } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangup->cause) {
1551 } else {
1553 }
1554 }
1555
1556 /* tv_usec is suseconds_t, which could be int or long */
1557 ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dur %.3f bill %.3f dispo %s\n",
1558 cdr->party_a.snapshot->base->name,
1559 (long)cdr->start.tv_sec,
1560 (long)cdr->start.tv_usec,
1561 (long)cdr->answer.tv_sec,
1562 (long)cdr->answer.tv_usec,
1563 (long)cdr->end.tv_sec,
1564 (long)cdr->end.tv_usec,
1565 (double)ast_tvdiff_ms(cdr->end, cdr->start) / 1000.0,
1566 (double)ast_tvdiff_ms(cdr->end, cdr->answer) / 1000.0,
1568}
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:1499
struct ast_channel_snapshot_hangup * hangup

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 2306 of file cdr.c.

2307{
2308 struct cdr_object *cdr = obj;
2309
2310 if (!strcasecmp(cdr->party_b_name, arg)) {
2311#ifdef AST_DEVMODE
2312 struct ast_channel_snapshot *party_b = data;
2313
2314 /*
2315 * For sanity's sake we also assert the party_b snapshot
2316 * is consistent with the key.
2317 */
2319 && !strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name));
2320#endif
2321
2322 /* Don't transition to the finalized state - let the Party A do
2323 * that when its ready
2324 */
2326 }
2327 return 0;
2328}

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

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 3368 of file cdr.c.

3369{
3370 struct ast_channel_snapshot *party_a = cdr_obj->party_a.snapshot;
3371 struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
3372
3373 if (!strcasecmp(name, "clid")) {
3374 ast_callerid_merge(value, length, party_a->caller->name, party_a->caller->number, "");
3375 } else if (!strcasecmp(name, "src")) {
3376 ast_copy_string(value, party_a->caller->number, length);
3377 } else if (!strcasecmp(name, "dst")) {
3378 ast_copy_string(value, party_a->dialplan->exten, length);
3379 } else if (!strcasecmp(name, "dcontext")) {
3380 ast_copy_string(value, party_a->dialplan->context, length);
3381 } else if (!strcasecmp(name, "channel")) {
3382 ast_copy_string(value, party_a->base->name, length);
3383 } else if (!strcasecmp(name, "dstchannel")) {
3384 if (party_b) {
3385 ast_copy_string(value, party_b->base->name, length);
3386 } else {
3387 ast_copy_string(value, "", length);
3388 }
3389 } else if (!strcasecmp(name, "lastapp")) {
3390 ast_copy_string(value, party_a->dialplan->appl, length);
3391 } else if (!strcasecmp(name, "lastdata")) {
3392 ast_copy_string(value, party_a->dialplan->data, length);
3393 } else if (!strcasecmp(name, "start")) {
3394 cdr_get_tv(cdr_obj->start, NULL, value, length);
3395 } else if (!strcasecmp(name, "answer")) {
3396 cdr_get_tv(cdr_obj->answer, NULL, value, length);
3397 } else if (!strcasecmp(name, "end")) {
3398 cdr_get_tv(cdr_obj->end, NULL, value, length);
3399 } else if (!strcasecmp(name, "duration")) {
3400 snprintf(value, length, "%ld", cdr_object_get_duration(cdr_obj));
3401 } else if (!strcasecmp(name, "billsec")) {
3402 snprintf(value, length, "%ld", cdr_object_get_billsec(cdr_obj));
3403 } else if (!strcasecmp(name, "disposition")) {
3404 snprintf(value, length, "%u", cdr_obj->disposition);
3405 } else if (!strcasecmp(name, "amaflags")) {
3406 snprintf(value, length, "%d", party_a->amaflags);
3407 } else if (!strcasecmp(name, "accountcode")) {
3408 ast_copy_string(value, party_a->base->accountcode, length);
3409 } else if (!strcasecmp(name, "peeraccount")) {
3410 if (party_b) {
3411 ast_copy_string(value, party_b->base->accountcode, length);
3412 } else {
3413 ast_copy_string(value, "", length);
3414 }
3415 } else if (!strcasecmp(name, "uniqueid")) {
3416 ast_copy_string(value, party_a->base->uniqueid, length);
3417 } else if (!strcasecmp(name, "linkedid")) {
3418 ast_copy_string(value, cdr_obj->linkedid, length);
3419 } else if (!strcasecmp(name, "tenantid")) {
3420 ast_copy_string(value, party_a->base->tenantid, length);
3421 } else if (!strcasecmp(name, "peertenantid")) {
3422 if (party_b) {
3423 ast_copy_string(value, party_b->base->tenantid, length);
3424 } else {
3425 ast_copy_string(value, "", length);
3426 }
3427 } else if (!strcasecmp(name, "userfield")) {
3428 ast_copy_string(value, cdr_obj->party_a.userfield, length);
3429 } else if (!strcasecmp(name, "sequence")) {
3430 snprintf(value, length, "%u", cdr_obj->sequence);
3431 } else {
3432 return 1;
3433 }
3434
3435 return 0;
3436}

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 3351 of file cdr.c.

3352{
3353 struct ast_var_t *variable;
3354
3355 AST_LIST_TRAVERSE(&cdr->party_a.variables, variable, entries) {
3356 if (!strcasecmp(name, ast_var_name(variable))) {
3357 ast_copy_string(value, ast_var_value(variable), length);
3358 return;
3359 }
3360 }
3361
3362 *value = '\0';
3363}

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 1330 of file cdr.c.

1331{
1332 long int ms;
1333
1334 if (ast_tvzero(cdr->answer)) {
1335 return 0;
1336 }
1337
1338 ms = ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->answer);
1339 if (ms % 1000 >= 500
1341 ms = (ms / 1000) + 1;
1342 } else {
1343 ms = ms / 1000;
1344 }
1345
1346 return ms;
1347}
@ CDR_INITIATED_SECONDS
Definition: cdr.h:225

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 3445 of file cdr.c.

3446{
3447 char *param;
3448
3449 if (ast_strlen_zero(name)) {
3450 return NULL;
3451 }
3452
3453 param = ast_strdupa(name);
3455}
static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
Definition: cdr.c:3266

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 3266 of file cdr.c.

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

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

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 1322 of file cdr.c.

1323{
1324 return (long)(ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->start) / 1000);
1325}

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 2483 of file cdr.c.

2484{
2485 struct cdr_object *cdr = obj;
2486 struct bridge_leave_data *leave_data = data;
2487
2488 if (cdr->fn_table == &bridge_state_fn_table
2489 && !strcmp(cdr->bridge, leave_data->bridge->uniqueid)
2490 && !strcasecmp(cdr->party_b_name, arg)) {
2491 /*
2492 * For sanity's sake we also assert the party_b snapshot
2493 * is consistent with the key.
2494 */
2496 && !strcasecmp(cdr->party_b.snapshot->base->name, leave_data->channel->base->name));
2497
2498 /* It is our Party B, in our bridge. Set the last event and let the handler
2499 * transition our CDR appropriately when we leave the bridge.
2500 */
2501 cdr->lastevent = *leave_data->lastevent;
2503 }
2504 return 0;
2505}
const struct timeval * lastevent
Definition: cdr.c:2479
struct ast_bridge_snapshot * bridge
Definition: cdr.c:2477
struct ast_channel_snapshot * channel
Definition: cdr.c:2478

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 1287 of file cdr.c.

1288{
1289 /* Check whether or not the party is dialed. A dialed party is never the
1290 * Party A with a party that was not dialed.
1291 */
1292 if (!snapshot_is_dialed(left->snapshot) && snapshot_is_dialed(right->snapshot)) {
1293 return left;
1294 } else if (snapshot_is_dialed(left->snapshot) && !snapshot_is_dialed(right->snapshot)) {
1295 return right;
1296 }
1297
1298 /* Try the Party A flag */
1300 return left;
1302 return right;
1303 }
1304
1305 /* Neither party is dialed and neither has the Party A flag - defer to
1306 * creation time */
1307 if (left->snapshot->base->creationtime.tv_sec < right->snapshot->base->creationtime.tv_sec) {
1308 return left;
1309 } else if (left->snapshot->base->creationtime.tv_sec > right->snapshot->base->creationtime.tv_sec) {
1310 return right;
1311 } else if (left->snapshot->base->creationtime.tv_usec > right->snapshot->base->creationtime.tv_usec) {
1312 return right;
1313 } else {
1314 /* Okay, fine, take the left one */
1315 return left;
1316 }
1317}
@ AST_CDR_FLAG_PARTY_A
Definition: cdr.h:246

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 3250 of file cdr.c.

3251{
3252 struct cdr_object *cdr = obj;
3253 const char *name = arg;
3254
3255 if (!strcasecmp(cdr->party_a.snapshot->base->name, name) ||
3256 (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->base->name, name))) {
3257 return CMP_MATCH;
3258 }
3259 return 0;
3260}

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

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 1499 of file cdr.c.

1500{
1501 /* Change the disposition based on the hang up cause */
1502 switch (hangupcause) {
1503 case AST_CAUSE_BUSY:
1505 break;
1509 } else {
1511 }
1512 break;
1516 break;
1520 break;
1521 default:
1522 break;
1523 }
1524}
#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 888 of file cdr.c.

889{
890 ao2_t_replace(dst->snapshot, src->snapshot, "CDR snapshot copy");
891 strcpy(dst->userfield, src->userfield);
892 dst->flags = src->flags;
893 copy_variables(&dst->variables, &src->variables);
894}
#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 1628 of file cdr.c.

1630{
1631 cdr_object_update_cid(old_snapshot, new_snapshot);
1632 ao2_t_replace(old_snapshot->snapshot, new_snapshot, "Swap CDR snapshot");
1633}
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:1603

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 902 of file cdr.c.

903{
904 CDR_DEBUG("%p - Transitioning CDR for %s from state %s to %s\n",
905 cdr, cdr->party_a.snapshot->base->name,
906 cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
907 cdr->fn_table = fn_table;
908
909 if (cdr->fn_table->init_function && do_init) {
910 cdr->fn_table->init_function(cdr);
911 }
912}
const char * name
Name of the subclass.
Definition: cdr.c:514
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:523

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 1603 of file cdr.c.

1604{
1605 if (!old_snapshot->snapshot) {
1606 set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1607 set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1608 set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1609 return;
1610 }
1611 if (strcmp(old_snapshot->snapshot->caller->dnid, new_snapshot->caller->dnid)) {
1612 set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1613 }
1614 if (strcmp(old_snapshot->snapshot->caller->subaddr, new_snapshot->caller->subaddr)) {
1615 set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1616 }
1617 if (strcmp(old_snapshot->snapshot->caller->dialed_subaddr, new_snapshot->caller->dialed_subaddr)) {
1618 set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1619 }
1620}
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_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 2330 of file cdr.c.

2331{
2332 struct cdr_object *cdr = obj;
2333
2334 if (cdr->fn_table->process_party_b
2335 && !strcasecmp(cdr->party_b_name, arg)) {
2336 struct ast_channel_snapshot *party_b = data;
2337
2338 /*
2339 * For sanity's sake we also check the party_b snapshot
2340 * for consistency with the key. The callback needs and
2341 * asserts the snapshot to be this way.
2342 */
2343 if (!cdr->party_b.snapshot
2344 || strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name)) {
2346 "CDR for Party A %s(%s) has inconsistent Party B %s name. Message can be ignored but this shouldn't happen.\n",
2347 cdr->linkedid,
2348 cdr->party_a.snapshot->base->name,
2349 cdr->party_b_name);
2350 return 0;
2351 }
2352
2353 cdr->fn_table->process_party_b(cdr, party_b);
2354 }
2355 return 0;
2356}
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:542

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, and cdr_object_snapshot::snapshot.

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 3588 of file cdr.c.

3589{
3590 struct cdr_object *cdr = obj;
3591
3592 if ((cdr->fn_table != &finalized_state_fn_table || !cdr->next)
3593 && !strcasecmp(cdr->party_b_name, arg)) {
3594 struct party_b_userfield_update *info = data;
3595
3596 /*
3597 * For sanity's sake we also assert the party_b snapshot
3598 * is consistent with the key.
3599 */
3601 && !strcasecmp(cdr->party_b.snapshot->base->name, info->channel_name));
3602
3603 ast_copy_string(cdr->party_b.userfield, info->userfield,
3604 sizeof(cdr->party_b.userfield));
3605 }
3606
3607 return 0;
3608}
def info(msg)

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

Referenced by ast_cdr_setuserfield().

◆ cdr_submit_batch()

static void cdr_submit_batch ( int  shutdown)
static

Definition at line 3899 of file cdr.c.

3900{
3901 struct module_config *mod_cfg;
3902 struct cdr_batch_item *oldbatchitems = NULL;
3903 pthread_t batch_post_thread = AST_PTHREADT_NULL;
3904
3905 /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
3906 if (!batch || !batch->head) {
3907 return;
3908 }
3909
3910 /* move the old CDRs aside, and prepare a new CDR batch */
3912 oldbatchitems = batch->head;
3913 reset_batch();
3915
3916 mod_cfg = ao2_global_obj_ref(module_configs);
3917
3918 /* if configured, spawn a new thread to post these CDRs,
3919 also try to save as much as possible if we are shutting down safely */
3920 if (!mod_cfg
3922 || do_shutdown) {
3923 ast_debug(1, "CDR single-threaded batch processing begins now\n");
3924 do_batch_backend_process(oldbatchitems);
3925 } else {
3926 if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
3927 ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
3928 do_batch_backend_process(oldbatchitems);
3929 } else {
3930 ast_debug(1, "CDR multi-threaded batch processing begins now\n");
3931 }
3932 }
3933
3934 ao2_cleanup(mod_cfg);
3935}
static void reset_batch(void)
Definition: cdr.c:3863
static void * do_batch_backend_process(void *data)
Definition: cdr.c:3882
@ BATCH_MODE_SCHEDULER_ONLY
Definition: cdr.h:234
struct ast_flags settings
Definition: cdr.h:272
struct ast_cdr_config::batch_settings batch_settings
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:597

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 4623 of file cdr.c.

4624{
4625 struct module_config *mod_cfg;
4626
4627 mod_cfg = ao2_global_obj_ref(module_configs);
4628 if (mod_cfg
4629 && ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4630 if (create_subscriptions()) {
4632 ast_log(AST_LOG_ERROR, "Failed to create Stasis subscriptions\n");
4633 ao2_cleanup(mod_cfg);
4634 return -1;
4635 }
4636 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4638 } else {
4639 ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
4640 }
4641 } else {
4643 ast_log(LOG_NOTICE, "CDR logging disabled.\n");
4644 }
4645 ao2_cleanup(mod_cfg);
4646
4647 return mod_cfg ? 0 : -1;
4648}
static int create_subscriptions(void)
Create the Stasis subscriptions for CDRs.
Definition: cdr.c:4450
static void cdr_enable_batch_mode(struct ast_cdr_config *config)
Definition: cdr.c:4555
static void destroy_subscriptions(void)
Destroy the active Stasis subscriptions.
Definition: cdr.c:4440
struct ast_flags settings
Definition: cdr.h:268

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 2359 of file cdr.c.

2361{
2362 /* If we're dead, we don't need a new CDR */
2363 if (!new_snapshot
2366 return 0;
2367 }
2368
2369 /* Auto-fall through will increment the priority but have no application */
2370 if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
2371 return 0;
2372 }
2373
2374 if (old_snapshot && !snapshot_cep_changed(old_snapshot, new_snapshot)) {
2375 return 0;
2376 }
2377
2378 return 1;
2379}
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:1243

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 4103 of file cdr.c.

4104{
4105 int wordlen = strlen(a->word);
4106 struct ao2_iterator it_cdrs;
4107 struct cdr_object *cdr;
4108
4110 while ((cdr = ao2_iterator_next(&it_cdrs))) {
4111 if (!strncasecmp(a->word, cdr->party_a.snapshot->base->name, wordlen)) {
4113 ao2_ref(cdr, -1);
4114 break;
4115 }
4116 }
4117 ao2_ref(cdr, -1);
4118 }
4119 ao2_iterator_destroy(&it_cdrs);
4120
4121 return NULL;
4122}
#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:2768
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, and cdr_object_snapshot::snapshot.

Referenced by handle_cli_show().

◆ cli_show_channel()

static void cli_show_channel ( struct ast_cli_args a)
static

Definition at line 4188 of file cdr.c.

4189{
4190 struct cdr_object *it_cdr;
4191 char clid[64];
4192 char start_time_buffer[64];
4193 char answer_time_buffer[64];
4194 char end_time_buffer[64];
4195 const char *channel_name = a->argv[3];
4196 struct cdr_object *cdr;
4197
4198#define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4199#define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4200
4201 cdr = cdr_object_get_by_name(channel_name);
4202 if (!cdr) {
4203 ast_cli(a->fd, "Unknown channel: %s\n", channel_name);
4204 return;
4205 }
4206
4207 ast_cli(a->fd, "\n");
4208 ast_cli(a->fd, "Call Detail Record (CDR) Information for %s\n", channel_name);
4209 ast_cli(a->fd, "--------------------------------------------------\n");
4210 ast_cli(a->fd, TITLE_STRING, "AccountCode", "CallerID", "Dst. Channel", "LastApp", "Data", "Start", "Answer", "End", "Billsec", "Duration");
4211
4212 ao2_lock(cdr);
4213 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4214 struct timeval end;
4215
4216 if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4217 continue;
4218 }
4219 ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller->name, it_cdr->party_a.snapshot->caller->number, "");
4220 if (ast_tvzero(it_cdr->end)) {
4221 end = ast_tvnow();
4222 } else {
4223 end = it_cdr->end;
4224 }
4225 cdr_get_tv(it_cdr->start, "%T", start_time_buffer, sizeof(start_time_buffer));
4226 cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4227 cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
4228 ast_cli(a->fd, FORMAT_STRING,
4229 it_cdr->party_a.snapshot->base->accountcode,
4230 clid,
4231 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4232 it_cdr->appl,
4233 it_cdr->data,
4234 start_time_buffer,
4235 answer_time_buffer,
4236 end_time_buffer,
4237 (long)ast_tvdiff_ms(end, it_cdr->answer) / 1000,
4238 (long)ast_tvdiff_ms(end, it_cdr->start) / 1000);
4239 }
4240 ao2_unlock(cdr);
4241
4242 ao2_cleanup(cdr);
4243
4244#undef FORMAT_STRING
4245#undef TITLE_STRING
4246}
#define FORMAT_STRING
#define TITLE_STRING
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
char * end
Definition: eagi_proxy.c:73

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 4124 of file cdr.c.

4125{
4126 struct ao2_iterator it_cdrs;
4127 struct cdr_object *cdr;
4128 char start_time_buffer[64];
4129 char answer_time_buffer[64];
4130 char end_time_buffer[64];
4131
4132#define TITLE_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4133#define FORMAT_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4134
4135 ast_cli(a->fd, "\n");
4136 ast_cli(a->fd, "Channels with Call Detail Record (CDR) Information\n");
4137 ast_cli(a->fd, "--------------------------------------------------\n");
4138 ast_cli(a->fd, TITLE_STRING, "Channel", "Dst. Channel", "LastApp", "Start", "Answer", "End", "Billsec", "Duration");
4139
4141 for (; (cdr = ao2_iterator_next(&it_cdrs)); ao2_cleanup(cdr)) {
4142 struct cdr_object *it_cdr;
4143 struct timeval start_time = { 0, };
4144 struct timeval answer_time = { 0, };
4145 struct timeval end_time = { 0, };
4146
4147 SCOPED_AO2LOCK(lock, cdr);
4148
4149 /* Calculate the start, end, answer, billsec, and duration over the
4150 * life of all of the CDR entries
4151 */
4152 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4153 if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4154 continue;
4155 }
4156 if (ast_tvzero(start_time)) {
4157 start_time = it_cdr->start;
4158 }
4159 if (!ast_tvzero(it_cdr->answer) && ast_tvzero(answer_time)) {
4160 answer_time = it_cdr->answer;
4161 }
4162 }
4163
4164 /* If there was no start time, then all CDRs were for a dialed channel; skip */
4165 if (ast_tvzero(start_time)) {
4166 continue;
4167 }
4168 it_cdr = cdr->last;
4169
4170 end_time = ast_tvzero(it_cdr->end) ? ast_tvnow() : it_cdr->end;
4171 cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
4172 cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4173 cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
4175 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4176 it_cdr->appl,
4177 start_time_buffer,
4178 answer_time_buffer,
4179 end_time_buffer,
4180 ast_tvzero(answer_time) ? 0 : (long)ast_tvdiff_ms(end_time, answer_time) / 1000,
4181 (long)ast_tvdiff_ms(end_time, start_time) / 1000);
4182 }
4183 ao2_iterator_destroy(&it_cdrs);
4184#undef FORMAT_STRING
4185#undef TITLE_STRING
4186}

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 843 of file cdr.c.

844{
845 struct ast_var_t *variables;
846 struct ast_var_t *newvariable;
847 const char *var;
848 const char *val;
849 int x = 0;
850
851 AST_LIST_TRAVERSE(from_list, variables, entries) {
852 var = ast_var_name(variables);
853 if (ast_strlen_zero(var)) {
854 continue;
855 }
856 val = ast_var_value(variables);
857 if (ast_strlen_zero(val)) {
858 continue;
859 }
860 newvariable = ast_var_assign(var, val);
861 if (newvariable) {
862 AST_LIST_INSERT_HEAD(to_list, newvariable, entries);
863 ++x;
864 }
865 }
866
867 return x;
868}
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
Definition: ast_expr2.c:325

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 4450 of file cdr.c.

4451{
4452 if (!cdr_topic) {
4453 return -1;
4454 }
4455
4457 return 0;
4458 }
4459
4461 if (!channel_subscription) {
4462 return -1;
4463 }
4465 if (!bridge_subscription) {
4466 return -1;
4467 }
4469 if (!parking_subscription) {
4470 return -1;
4471 }
4472
4473 return 0;
4474}
static struct stasis_forward * bridge_subscription
Our subscription for bridges.
Definition: cdr.c:470
static struct stasis_forward * channel_subscription
Our subscription for channels.
Definition: cdr.c:473
static struct stasis_forward * parking_subscription
Our subscription for parking.
Definition: cdr.c:476
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:1605
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

Destroy the active Stasis subscriptions.

Definition at line 4440 of file cdr.c.

References bridge_subscription, channel_subscription, parking_subscription, and stasis_forward_cancel().

Referenced by cdr_toggle_runtime_options(), and unload_module().

◆ 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 1977 of file cdr.c.

1978{
1979 int success = 0;
1980
1981 ast_string_field_set(cdr, bridge, bridge->uniqueid);
1982
1983 /* Get parties in the bridge */
1984 if (ao2_container_count(bridge->channels) == 1) {
1985 /* No one in the bridge yet but us! */
1988 }
1989
1990 /* If we don't have a Party B (originated channel), skip it */
1991 if (cdr->party_b.snapshot) {
1992 struct ao2_iterator it_cdrs;
1993 char *channel_id;
1994
1995 for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
1996 !success && (channel_id = ao2_iterator_next(&it_cdrs));
1997 ao2_ref(channel_id, -1)) {
1998 struct cdr_object *cand_cdr_master;
1999 struct cdr_object *cand_cdr;
2000
2001 cand_cdr_master = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
2002 if (!cand_cdr_master) {
2003 continue;
2004 }
2005
2006 ao2_lock(cand_cdr_master);
2007 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
2008 /* Skip any records that are not in a bridge or in this bridge.
2009 * I'm not sure how that would happen, but it pays to be careful. */
2010 if (cand_cdr->fn_table != &bridge_state_fn_table
2011 || strcmp(cdr->bridge, cand_cdr->bridge)) {
2012 continue;
2013 }
2014
2015 /* Skip any records that aren't our Party B */
2016 if (strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
2017 continue;
2018 }
2019 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
2020 /* If they have a Party B, they joined up with someone else as their
2021 * Party A. Don't finalize them as they're active. Otherwise, we
2022 * have stolen them so they need to be finalized.
2023 */
2024 if (!cand_cdr->party_b.snapshot) {
2025 cdr_object_finalize(cand_cdr);
2026 }
2027 success = 1;
2028 break;
2029 }
2030 ao2_unlock(cand_cdr_master);
2031 ao2_cleanup(cand_cdr_master);
2032 }
2033 ao2_iterator_destroy(&it_cdrs);
2034 }
2035
2036 /* We always transition state, even if we didn't get a peer */
2038
2039 /* Success implies that we have a Party B */
2040 if (success) {
2042 }
2044}
#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, cdr_object::fn_table, ast_channel_snapshot_base::name, cdr_object::next, OBJ_SEARCH_KEY, cdr_object::party_a, cdr_object::party_b, and cdr_object_snapshot::snapshot.

◆ 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 1913 of file cdr.c.

1914{
1915 /* Don't process a begin dial here. A party A already in the dial state will
1916 * who receives a dial begin for something else will be handled by the
1917 * message router callback and will add a new CDR for the party A */
1918 return 1;
1919}

◆ 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 1945 of file cdr.c.

1946{
1947 struct ast_channel_snapshot *party_a;
1948
1949 if (caller) {
1950 party_a = caller;
1951 } else {
1952 party_a = peer;
1953 }
1954 ast_assert(!strcasecmp(cdr->party_a.snapshot->base->name, party_a->base->name));
1955 cdr_object_swap_snapshot(&cdr->party_a, party_a);
1956
1957 if (cdr->party_b.snapshot) {
1958 if (strcasecmp(cdr->party_b.snapshot->base->name, peer->base->name)) {
1959 /* Not the status for this CDR - defer back to the message router */
1960 return 1;
1961 }
1963 }
1964
1965 /* Set the disposition based on the dial string. */
1966 cdr->disposition = dial_status_to_disposition(dial_status);
1967 if (cdr->disposition == AST_CDR_ANSWERED) {
1968 /* Switch to dial pending to wait and see what the caller does */
1970 } else {
1972 }
1973
1974 return 0;
1975}
static enum ast_cdr_disposition dial_status_to_disposition(const char *dial_status)
Definition: cdr.c:1925
struct cdr_object_fn_table dialed_pending_state_fn_table
The virtual table for the Dialed Pending state.
Definition: cdr.c:733

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 2186 of file cdr.c.

2187{
2188 return (strcmp(dialstatus, "RINGING") &&
2189 strcmp(dialstatus, "PROCEEDING") &&
2190 strcmp(dialstatus, "PROGRESS"));
2191}

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 1925 of file cdr.c.

1926{
1927 if (!strcmp(dial_status, "ANSWER")) {
1928 return AST_CDR_ANSWERED;
1929 } else if (!strcmp(dial_status, "BUSY")) {
1930 return AST_CDR_BUSY;
1931 } else if (!strcmp(dial_status, "CANCEL") || !strcmp(dial_status, "NOANSWER")) {
1932 return AST_CDR_NOANSWER;
1933 } else if (!strcmp(dial_status, "CONGESTION")) {
1935 return AST_CDR_FAILED;
1936 } else {
1937 return AST_CDR_CONGESTION;
1938 }
1939 } else if (!strcmp(dial_status, "FAILED")) {
1940 return AST_CDR_FAILED;
1941 }
1942 return AST_CDR_FAILED;
1943}

References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_CONGESTION, AST_CDR_FAILED, AST_CDR_NOANSWER, CDR_CONGESTION, and is_cdr_flag_set().

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 2073 of file cdr.c.

2074{
2076 return cdr->fn_table->process_bridge_enter(cdr, bridge, channel);
2077}
struct cdr_object_fn_table dial_state_fn_table
The virtual table for the Dial state.
Definition: cdr.c:700
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:599

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 2089 of file cdr.c.

2090{
2092
2093 /* Ask for a new CDR */
2094 return 1;
2095}

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 2079 of file cdr.c.

2080{
2081 if (cdr->party_b.snapshot) {
2082 /* We can't handle this as we have a Party B - ask for a new one */
2083 return 1;
2084 }
2086 return 0;
2087}
struct cdr_object_fn_table parked_state_fn_table
The virtual table for the Parked state.
Definition: cdr.c:774

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 2048 of file cdr.c.

2049{
2050 /* If we get a CEP change, we're executing dialplan. If we have a Party B
2051 * that means we need a new CDR; otherwise, switch us over to single.
2052 */
2053 if (snapshot_cep_changed(cdr->party_a.snapshot, snapshot)) {
2054 if (cdr->party_b.snapshot) {
2056 cdr->fn_table->process_party_a(cdr, snapshot);
2057 return 1;
2058 } else {
2059 /* The CDR does not need to be reinitialized when transitioning
2060 * to its single state as this would overwrite the start time,
2061 * causing potentially both the answer and the start time to be
2062 * the same which is incorrect.
2063 */
2065 cdr->fn_table->process_party_a(cdr, snapshot);
2066 return 0;
2067 }
2068 }
2069 base_process_party_a(cdr, snapshot);
2070 return 0;
2071}
static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition: cdr.c:1637

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 3882 of file cdr.c.

3883{
3884 struct cdr_batch_item *processeditem;
3885 struct cdr_batch_item *batchitem = data;
3886
3887 /* Push each CDR into storage mechanism(s) and free all the memory */
3888 while (batchitem) {
3889 post_cdr(batchitem->cdr);
3890 ast_cdr_free(batchitem->cdr);
3891 processeditem = batchitem;
3892 batchitem = batchitem->next;
3893 ast_free(processeditem);
3894 }
3895
3896 return NULL;
3897}

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 4036 of file cdr.c.

4037{
4038 struct timespec timeout;
4039 int schedms;
4040 int numevents = 0;
4041
4042 for (;;) {
4043 struct timeval now;
4044 schedms = ast_sched_wait(sched);
4045 /* this shouldn't happen, but provide a 1 second default just in case */
4046 if (schedms < 0)
4047 schedms = 1000;
4048 now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
4049 timeout.tv_sec = now.tv_sec;
4050 timeout.tv_nsec = now.tv_usec * 1000;
4051 /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
4054 numevents = ast_sched_runq(sched);
4056 ast_debug(2, "Processed %d CDR batches from the run queue\n", numevents);
4057 }
4058
4059 return NULL;
4060}
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:457
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:210
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:2282

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 2508 of file cdr.c.

2509{
2510 /* Ignore holding bridge technology messages. We treat this simply as an application
2511 * that a channel enters into.
2512 */
2513 if (!strcmp(bridge->technology, "holding_bridge") && strcmp(bridge->subclass, "parking")) {
2514 return 1;
2515 }
2516 return 0;
2517}
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 2161 of file cdr.c.

2162{
2163 return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
2164}
@ 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 2170 of file cdr.c.

2172{
2173 int ret = 0;
2174
2175 /* Drop cache updates from certain channel technologies */
2176 if (old_snapshot) {
2177 ret |= filter_channel_snapshot(old_snapshot);
2178 }
2179 if (new_snapshot) {
2180 ret |= filter_channel_snapshot(new_snapshot);
2181 }
2182
2183 return ret;
2184}
static int filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
Definition: cdr.c:2161

References filter_channel_snapshot().

Referenced by handle_channel_snapshot_update_message().

◆ finalize_batch_mode()

static void finalize_batch_mode ( void  )
static

Definition at line 4413 of file cdr.c.

4414{
4416 return;
4417 }
4418 /* wake up the thread so it will exit */
4419 pthread_cancel(cdr_thread);
4420 pthread_kill(cdr_thread, SIGURG);
4421 pthread_join(cdr_thread, NULL);
4425}
void ast_cdr_engine_term(void)
Definition: cdr.c:4736
#define ast_cond_destroy(cond)
Definition: lock.h:206

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

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 2141 of file cdr.c.

2142{
2144}

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 2146 of file cdr.c.

2147{
2150 return 0;
2151 }
2152
2153 /* Indicate that, if possible, we should get a new CDR */
2154 return 1;
2155}

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 874 of file cdr.c.

875{
876 struct ast_var_t *vardata;
877
878 while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
879 ast_var_delete(vardata);
880 }
881}

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 2830 of file cdr.c.

2832{
2834 struct ast_bridge_snapshot *bridge = update->bridge;
2835 struct ast_channel_snapshot *channel = update->channel;
2836 struct cdr_object *cdr;
2837
2839 return;
2840 }
2841
2842 if (filter_channel_snapshot(channel)) {
2843 return;
2844 }
2845
2846 CDR_DEBUG("Bridge Enter message for channel %s: %u.%08u\n",
2847 channel->base->name,
2848 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2849 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2850
2852 if (!cdr) {
2853 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2854 ast_assert(0);
2855 return;
2856 }
2857
2858 if (!strcmp(bridge->subclass, "parking")) {
2860 } else {
2862 }
2863 ao2_cleanup(cdr);
2864}
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:2750
static int filter_bridge_messages(struct ast_bridge_snapshot *bridge)
Filter bridge messages based on bridge technology.
Definition: cdr.c:2508
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:2708
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, 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 2525 of file cdr.c.

2527{
2529 struct ast_bridge_snapshot *bridge = update->bridge;
2530 struct ast_channel_snapshot *channel = update->channel;
2531 struct cdr_object *cdr;
2532 struct cdr_object *it_cdr;
2533 struct bridge_leave_data leave_data = {
2534 .bridge = bridge,
2535 .channel = channel,
2536 .lastevent = stasis_message_timestamp(message)
2537 };
2538 int left_bridge = 0;
2539
2541 return;
2542 }
2543
2545 return;
2546 }
2547
2548 CDR_DEBUG("Bridge Leave message for %s: %u.%08u\n",
2549 channel->base->name,
2550 (unsigned int)leave_data.lastevent->tv_sec,
2551 (unsigned int)leave_data.lastevent->tv_usec);
2552
2554 if (!cdr) {
2555 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2556 ast_assert(0);
2557 return;
2558 }
2559
2560 /* Party A */
2561 ao2_lock(cdr);
2562 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2563 it_cdr->lastevent = *leave_data.lastevent;
2564 if (!it_cdr->fn_table->process_bridge_leave) {
2565 continue;
2566 }
2567 CDR_DEBUG("%p - Processing Bridge Leave for %s\n",
2568 it_cdr, channel->base->name);
2569 if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
2570 ast_string_field_set(it_cdr, bridge, "");
2571 left_bridge = 1;
2572 }
2573 }
2574 ao2_unlock(cdr);
2575
2576 /* Party B */
2577 if (left_bridge
2578 && strcmp(bridge->subclass, "parking")) {
2580 cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->base->name,
2581 &leave_data);
2582 }
2583
2584 ao2_cleanup(cdr);
2585}
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:2483
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:629

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, 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 2682 of file cdr.c.

2683{
2684 struct ao2_iterator it_channels;
2685 char *channel_id;
2686
2687 it_channels = ao2_iterator_init(bridge->channels, 0);
2688 while ((channel_id = ao2_iterator_next(&it_channels))) {
2689 struct cdr_object *cand_cdr;
2690
2691 cand_cdr = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
2692 if (cand_cdr) {
2693 bridge_candidate_process(cdr, cand_cdr);
2694 ao2_ref(cand_cdr, -1);
2695 }
2696
2697 ao2_ref(channel_id, -1);
2698 }
2699 ao2_iterator_destroy(&it_channels);
2700}
static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr)
Process a single bridge_candidate.
Definition: cdr.c:2624

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

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 2940 of file cdr.c.

2942{
2943 return;
2944}

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 2387 of file cdr.c.

2388{
2389 struct cdr_object *cdr;
2391 struct cdr_object *it_cdr;
2392
2393 if (filter_channel_snapshot_message(update->old_snapshot, update->new_snapshot)) {
2394 return;
2395 }
2396
2397 if (update->new_snapshot && !update->old_snapshot) {
2398 struct module_config *mod_cfg = NULL;
2399
2401 if (!cdr) {
2402 return;
2403 }
2404 mod_cfg = ao2_global_obj_ref(module_configs);
2405 cdr->is_root = 1;
2407
2408 /* If CDR should be disabled unless enabled on a per-channel basis, then disable
2409 CDR, right from the get go */
2410 if (mod_cfg) {
2412 ast_debug(3, "Disable CDR by default\n");
2414 }
2415 ao2_cleanup(mod_cfg);
2416 }
2417 } else {
2418 cdr = ao2_find(active_cdrs_master, update->new_snapshot->base->uniqueid, OBJ_SEARCH_KEY);
2419 }
2420
2421 /* Handle Party A */
2422 if (!cdr) {
2423 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->base->name);
2424 ast_assert(0);
2425 } else {
2426 int all_reject = 1;
2427
2428 ao2_lock(cdr);
2429 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2431 if (!it_cdr->fn_table->process_party_a) {
2432 continue;
2433 }
2434 all_reject &= it_cdr->fn_table->process_party_a(it_cdr, update->new_snapshot);
2435 }
2436 if (all_reject && check_new_cdr_needed(update->old_snapshot, update->new_snapshot)) {
2437 /* We're not hung up and we have a new snapshot - we need a new CDR */
2438 struct cdr_object *new_cdr;
2439
2441 if (new_cdr) {
2442 new_cdr->fn_table->process_party_a(new_cdr, update->new_snapshot);
2443 }
2444 }
2445 ao2_unlock(cdr);
2446 }
2447
2448 if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
2449 ao2_lock(cdr);
2450 CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->base->name);
2451 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2453 cdr_object_finalize(it_cdr);
2454 }
2456 ao2_unlock(cdr);
2457
2458 cdr_all_unlink(cdr);
2460 }
2461
2462 /* Handle Party B */
2463 if (update->new_snapshot) {
2465 cdr_object_update_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
2466 }
2467
2468 if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
2470 cdr_object_finalize_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
2471 }
2472
2473 ao2_cleanup(cdr);
2474}
#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:2330
static int cdr_object_finalize_party_b(void *obj, void *arg, void *data, int flags)
Definition: cdr.c:2306
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:2359
static int filter_channel_snapshot_message(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Definition: cdr.c:2170
@ 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::next, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_SEARCH_KEY, cdr_object_fn_table::process_party_a, ast_cdr_config::settings, 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 4062 of file cdr.c.

4063{
4064 struct module_config *mod_cfg;
4065
4066 switch (cmd) {
4067 case CLI_INIT:
4068 e->command = "cdr set debug [on|off]";
4069 e->usage = "Enable or disable extra debugging in the CDR Engine. Note\n"
4070 "that this will dump debug information to the VERBOSE setting\n"
4071 "and should only be used when debugging information from the\n"
4072 "CDR engine is needed.\n";
4073 return NULL;
4074 case CLI_GENERATE:
4075 return NULL;
4076 }
4077
4078 if (a->argc != 4) {
4079 return CLI_SHOWUSAGE;
4080 }
4081
4082 mod_cfg = ao2_global_obj_ref(module_configs);
4083 if (!mod_cfg) {
4084 ast_cli(a->fd, "Could not set CDR debugging mode\n");
4085 return CLI_SUCCESS;
4086 }
4087 if (!strcasecmp(a->argv[3], "on")
4088 && !ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
4090 ast_cli(a->fd, "CDR debugging enabled\n");
4091 } else if (!strcasecmp(a->argv[3], "off")
4092 && ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
4094 ast_cli(a->fd, "CDR debugging disabled\n");
4095 }
4096 cdr_set_debug_mode(mod_cfg);
4097 ao2_cleanup(mod_cfg);
4098
4099 return CLI_SUCCESS;
4100}
#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 4248 of file cdr.c.

4249{
4250 switch (cmd) {
4251 case CLI_INIT:
4252 e->command = "cdr show active";
4253 e->usage =
4254 "Usage: cdr show active [channel]\n"
4255 " Displays a summary of all Call Detail Records when [channel]\n"
4256 " is omitted; displays all of the Call Detail Records\n"
4257 " currently in flight for a given [channel] when [channel] is\n"
4258 " specified.\n\n"
4259 " Note that this will not display Call Detail Records that\n"
4260 " have already been dispatched to a backend storage, nor for\n"
4261 " channels that are no longer active.\n";
4262 return NULL;
4263 case CLI_GENERATE:
4264 return cli_complete_show(a);
4265 }
4266
4267 if (a->argc > 4) {
4268 return CLI_SHOWUSAGE;
4269 } else if (a->argc < 4) {
4271 } else {
4273 }
4274
4275 return CLI_SUCCESS;
4276}
static void cli_show_channels(struct ast_cli_args *a)
Definition: cdr.c:4124
static char * cli_complete_show(struct ast_cli_args *a)
Complete user input for 'cdr show'.
Definition: cdr.c:4103
static void cli_show_channel(struct ast_cli_args *a)
Definition: cdr.c:4188

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 4278 of file cdr.c.

4279{
4280 struct cdr_beitem *beitem = NULL;
4281 struct module_config *mod_cfg;
4282 int cnt = 0;
4283 long nextbatchtime = 0;
4284
4285 switch (cmd) {
4286 case CLI_INIT:
4287 e->command = "cdr show status";
4288 e->usage =
4289 "Usage: cdr show status\n"
4290 " Displays the Call Detail Record engine system status.\n";
4291 return NULL;
4292 case CLI_GENERATE:
4293 return NULL;
4294 }
4295
4296 if (a->argc > 3) {
4297 return CLI_SHOWUSAGE;
4298 }
4299
4300 mod_cfg = ao2_global_obj_ref(module_configs);
4301 if (!mod_cfg) {
4302 return CLI_FAILURE;
4303 }
4304
4305 ast_cli(a->fd, "\n");
4306 ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
4307 ast_cli(a->fd, "----------------------------------\n");
4308 ast_cli(a->fd, " Logging: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) ? "Enabled" : "Disabled");
4309 ast_cli(a->fd, " Mode: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE) ? "Batch" : "Simple");
4310 if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4311 ast_cli(a->fd, " Log calls by default: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_CHANNEL_DEFAULT_ENABLED) ? "Yes" : "No");
4312 ast_cli(a->fd, " Log unanswered calls: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) ? "Yes" : "No");
4313 ast_cli(a->fd, " Log congestion: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION) ? "Yes" : "No");
4314 ast_cli(a->fd, " Ignore bridging changes: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_STATE_CHANGES) ? "Yes" : "No");
4315 ast_cli(a->fd, " Ignore dial state changes: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_DIAL_CHANGES) ? "Yes" : "No");
4316 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4317 ast_cli(a->fd, "* Batch Mode Settings\n");
4318 ast_cli(a->fd, " -------------------\n");
4319 if (batch)
4320 cnt = batch->size;
4321 if (cdr_sched > -1)
4322 nextbatchtime = ast_sched_when(sched, cdr_sched);
4323 ast_cli(a->fd, " Safe shutdown: %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN) ? "Enabled" : "Disabled");
4324 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");
4325 ast_cli(a->fd, " Current batch size: %d record%s\n", cnt, ESS(cnt));
4326 ast_cli(a->fd, " Maximum batch size: %u record%s\n", mod_cfg->general->batch_settings.size, ESS(mod_cfg->general->batch_settings.size));
4327 ast_cli(a->fd, " Maximum batch time: %u second%s\n", mod_cfg->general->batch_settings.time, ESS(mod_cfg->general->batch_settings.time));
4328 ast_cli(a->fd, " Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
4329 }
4330 ast_cli(a->fd, "* Registered Backends\n");
4331 ast_cli(a->fd, " -------------------\n");
4333 if (AST_RWLIST_EMPTY(&be_list)) {
4334 ast_cli(a->fd, " (none)\n");
4335 } else {
4336 AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
4337 ast_cli(a->fd, " %s%s\n", beitem->name, beitem->suspended ? " (suspended) " : "");
4338 }
4339 }
4341 ast_cli(a->fd, "\n");
4342 }
4343
4344 ao2_cleanup(mod_cfg);
4345 return CLI_SUCCESS;
4346}
static int cdr_sched
Definition: cdr.c:449
@ 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
Definition: linkedlists.h:452
#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_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, 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 4348 of file cdr.c.

4349{
4350 struct module_config *mod_cfg;
4351
4352 switch (cmd) {
4353 case CLI_INIT:
4354 e->command = "cdr submit";
4355 e->usage =
4356 "Usage: cdr submit\n"
4357 "Posts all pending batched CDR data to the configured CDR\n"
4358 "backend engine modules.\n";
4359 return NULL;
4360 case CLI_GENERATE:
4361 return NULL;
4362 }
4363 if (a->argc > 2) {
4364 return CLI_SHOWUSAGE;
4365 }
4366
4367 mod_cfg = ao2_global_obj_ref(module_configs);
4368 if (!mod_cfg) {
4369 return CLI_FAILURE;
4370 }
4371
4372 if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4373 ast_cli(a->fd, "Cannot submit CDR batch: CDR engine disabled.\n");
4374 } else if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4375 ast_cli(a->fd, "Cannot submit CDR batch: batch mode not enabled.\n");
4376 } else {
4378 ast_cli(a->fd, "Submitted CDRs to backend engines for processing. This may take a while.\n");
4379 }
4380 ao2_cleanup(mod_cfg);
4381
4382 return CLI_SUCCESS;
4383}

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 2201 of file cdr.c.

2202{
2203 struct cdr_object *cdr;
2206 struct ast_channel_snapshot *peer;
2207 struct cdr_object *it_cdr;
2208 struct ast_json *dial_status_blob;
2209 const char *dial_status = NULL;
2210 int res = 1;
2211
2212 caller = ast_multi_channel_blob_get_channel(payload, "caller");
2213 peer = ast_multi_channel_blob_get_channel(payload, "peer");
2214 if (!peer && !caller) {
2215 return;
2216 }
2217
2218 if (peer && filter_channel_snapshot(peer)) {
2219 return;
2220 }
2221
2222 if (caller && filter_channel_snapshot(caller)) {
2223 return;
2224 }
2225
2226 dial_status_blob = ast_json_object_get(ast_multi_channel_blob_get_json(payload), "dialstatus");
2227 if (dial_status_blob) {
2228 dial_status = ast_json_string_get(dial_status_blob);
2229 }
2230
2231 CDR_DEBUG("Dial %s message for %s, %s: %u.%08u\n",
2232 ast_strlen_zero(dial_status) ? "Begin" : "End",
2233 caller ? caller->base->name : "(none)",
2234 peer ? peer->base->name : "(none)",
2235 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2236 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2237
2238 /* Figure out who is running this show */
2239 if (caller) {
2241 } else {
2243 }
2244 if (!cdr) {
2245 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->base->name : peer->base->name);
2246 ast_assert(0);
2247 return;
2248 }
2249
2250 ao2_lock(cdr);
2251 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2253 if (ast_strlen_zero(dial_status)) {
2254 if (!it_cdr->fn_table->process_dial_begin) {
2255 continue;
2256 }
2258 CDR_DEBUG("%p - Ignoring Dial Begin message\n", it_cdr);
2259 continue;
2260 }
2261 CDR_DEBUG("%p - Processing Dial Begin message for channel %s, peer %s\n",
2262 it_cdr,
2263 caller ? caller->base->name : "(none)",
2264 peer ? peer->base->name : "(none)");
2265 res &= it_cdr->fn_table->process_dial_begin(it_cdr,
2266 caller,
2267 peer);
2268 } else if (dial_status_end(dial_status)) {
2269 if (!it_cdr->fn_table->process_dial_end) {
2270 continue;
2271 }
2273 /* Set the disposition, and do nothing else. */
2274 it_cdr->disposition = dial_status_to_disposition(dial_status);
2275 CDR_DEBUG("%p - Setting disposition and that's it (%s)\n", it_cdr, dial_status);
2276 continue;
2277 }
2278 CDR_DEBUG("%p - Processing Dial End message for channel %s, peer %s\n",
2279 it_cdr,
2280 caller ? caller->base->name : "(none)",
2281 peer ? peer->base->name : "(none)");
2282 it_cdr->fn_table->process_dial_end(it_cdr,
2283 caller,
2284 peer,
2285 dial_status);
2286 }
2287 }
2288
2289 /* If we're ignoring dial changes, don't allow multiple CDRs for this channel. */
2290 if (!dial_changes_ignored) {
2291 /* If no CDR handled a dial begin message, make a new one */
2292 if (res && ast_strlen_zero(dial_status)) {
2293 struct cdr_object *new_cdr;
2294
2296 if (new_cdr) {
2297 new_cdr->fn_table->process_dial_begin(new_cdr, caller, peer);
2298 }
2299 }
2300 }
2301
2302 ao2_unlock(cdr);
2303 ao2_cleanup(cdr);
2304}
static int dial_changes_ignored
Definition: cdr.c:304
static int dial_status_end(const char *dialstatus)
Definition: cdr.c:2186
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:576
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:558

References active_cdrs_master, ao2_cleanup, ao2_find, ao2_lock, ao2_unlock, ast_assert, 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, 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 2872 of file cdr.c.

2874{
2876 struct ast_channel_snapshot *channel = payload->parkee;
2877 struct cdr_object *cdr;
2878 int unhandled = 1;
2879 struct cdr_object *it_cdr;
2880
2881 /* Anything other than getting parked will be handled by other updates */
2882 if (payload->event_type != PARKED_CALL) {
2883 return;
2884 }
2885
2886 /* No one got parked? */
2887 if (!channel) {
2888 return;
2889 }
2890
2891 if (filter_channel_snapshot(channel)) {
2892 return;
2893 }
2894
2895 CDR_DEBUG("Parked Call message for channel %s: %u.%08u\n",
2896 channel->base->name,
2897 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2898 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2899
2901 if (!cdr) {
2902 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2903 ast_assert(0);
2904 return;
2905 }
2906
2907 ao2_lock(cdr);
2908
2909 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2911 if (it_cdr->fn_table->process_parked_channel) {
2912 unhandled &= it_cdr->fn_table->process_parked_channel(it_cdr, payload);
2913 }
2914 }
2915
2916 if (unhandled) {
2917 /* Nothing handled the message - we need a new one! */
2918 struct cdr_object *new_cdr;
2919
2921 if (new_cdr) {
2922 /* As the new CDR is created in the single state, it is guaranteed
2923 * to have a function for the parked call message and will handle
2924 * the message */
2925 new_cdr->fn_table->process_parked_channel(new_cdr, payload);
2926 }
2927 }
2928
2929 ao2_unlock(cdr);
2930
2931 ao2_cleanup(cdr);
2932}
@ 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
int(*const process_parked_channel)(struct cdr_object *cdr, struct ast_parked_call_payload *parking_info)
Process an update informing us that the channel got itself parked.
Definition: cdr.c:642

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(), cdr_object::fn_table, cdr_object::lastevent, ast_channel_snapshot_base::name, cdr_object::next, OBJ_SEARCH_KEY, PARKED_CALL, ast_parked_call_payload::parkee, cdr_object_fn_table::process_parked_channel, 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 2708 of file cdr.c.

2712{
2713 int res = 1;
2714 struct cdr_object *it_cdr;
2715 struct cdr_object *new_cdr;
2716
2717 ao2_lock(cdr);
2718
2719 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2720 it_cdr->lastevent = *event_time;
2721
2723 res &= it_cdr->fn_table->process_parking_bridge_enter(it_cdr, bridge, channel);
2724 }
2725 if (it_cdr->fn_table->process_party_a) {
2726 CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
2727 channel->base->name);
2728 it_cdr->fn_table->process_party_a(it_cdr, channel);
2729 }
2730 }
2731
2732 if (res) {
2733 /* No one handled it - we need a new one! */
2734 new_cdr = cdr_object_create_and_append(cdr, event_time);
2735 if (new_cdr) {
2736 /* Let the single state transition us to Parked */
2738 new_cdr->fn_table->process_parking_bridge_enter(new_cdr, bridge, channel);
2739 }
2740 }
2741 ao2_unlock(cdr);
2742}
int(*const process_parking_bridge_enter)(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Process entering into a parking bridge.
Definition: cdr.c:615

References ao2_lock, ao2_unlock, ast_channel_snapshot::base, cdr_object::bridge, CDR_DEBUG, cdr_object_create_and_append(), cdr_object_transition_state(), cdr_object::fn_table, cdr_object::lastevent, ast_channel_snapshot_base::name, cdr_object::next, cdr_object_fn_table::process_parking_bridge_enter, cdr_object_fn_table::process_party_a, and single_state_fn_table.

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 2750 of file cdr.c.

2754{
2756 struct cdr_object *it_cdr;
2757 struct cdr_object *new_cdr;
2758 struct cdr_object *handled_cdr = NULL;
2759
2760 ao2_lock(cdr);
2761
2762try_again:
2763 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2764 it_cdr->lastevent = *event_time;
2765
2766 if (it_cdr->fn_table->process_party_a) {
2767 CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
2768 channel->base->name);
2769 it_cdr->fn_table->process_party_a(it_cdr, channel);
2770 }
2771
2772 /* Notify all states that they have entered a bridge */
2773 if (it_cdr->fn_table->process_bridge_enter) {
2774 CDR_DEBUG("%p - Processing bridge enter for %s\n", it_cdr,
2775 channel->base->name);
2776 result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
2777 switch (result) {
2779 /* Fall through */
2781 if (!handled_cdr) {
2782 handled_cdr = it_cdr;
2783 }
2784 break;
2786 /* Pass */
2787 break;
2789 /* We didn't win on any - end this CDR. If someone else comes in later
2790 * that is Party B to this CDR, it can re-activate this CDR.
2791 */
2792 if (!handled_cdr) {
2793 handled_cdr = it_cdr;
2794 }
2796 break;
2797 }
2798 }
2799 }
2800
2801 /* Create the new matchings, but only for either:
2802 * * The first CDR in the chain that handled it. This avoids issues with
2803 * forked CDRs.
2804 * * If no one handled it, the last CDR in the chain. This would occur if
2805 * a CDR joined a bridge and it wasn't Party A for anyone. We still need
2806 * to make pairings with everyone in the bridge.
2807 */
2808 if (handled_cdr) {
2809 handle_bridge_pairings(handled_cdr, bridge);
2810 } else {
2811 /* Nothing handled it - we need a new one! */
2812 new_cdr = cdr_object_create_and_append(cdr, event_time);
2813 if (new_cdr) {
2814 /* This is guaranteed to succeed: the new CDR is created in the single state
2815 * and will be able to handle the bridge enter message
2816 */
2817 goto try_again;
2818 }
2819 }
2820 ao2_unlock(cdr);
2821}
process_bridge_enter_results
Return types for process_bridge_enter functions.
Definition: cdr.c:487
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:2682
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(), cdr_object::fn_table, handle_bridge_pairings(), cdr_object::lastevent, ast_channel_snapshot_base::name, cdr_object::next, NULL, cdr_object_fn_table::process_bridge_enter, cdr_object_fn_table::process_party_a, and result.

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 3871 of file cdr.c.

3872{
3873 /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
3874 if (!(batch = ast_malloc(sizeof(*batch))))
3875 return -1;
3876
3877 reset_batch();
3878
3879 return 0;
3880}
#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 4657 of file cdr.c.

4658{
4659 struct module_config *mod_cfg = NULL;
4660 if (process_config(0)) {
4662 }
4663
4664 cdr_topic = stasis_topic_create("cdr:aggregator");
4665 if (!cdr_topic) {
4667 }
4668
4670 if (!stasis_router) {
4672 }
4675
4676 if (STASIS_MESSAGE_TYPE_INIT(cdr_sync_message_type)) {
4678 }
4679
4680 mod_cfg = ao2_global_obj_ref(module_configs);
4681
4683
4684 /* Always process dial messages, because even if we ignore most of it, we do want the dial status for the disposition. */
4686 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_DIAL_CHANGES)) {
4688 } else {
4690 CDR_DEBUG("Dial messages will be mostly ignored\n");
4691 }
4692
4693 /* If explicitly instructed to ignore call state changes, then ignore bridging events, parking, etc. */
4694 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_STATE_CHANGES)) {
4698 } else {
4699 CDR_DEBUG("All bridge and parking messages will be ignored\n");
4700 }
4701
4703
4704 if (mod_cfg) {
4705 ao2_cleanup(mod_cfg);
4706 } else {
4707 ast_log(LOG_WARNING, "Unable to obtain CDR configuration during module load?\n");
4708 }
4709
4712 if (!active_cdrs_master) {
4714 }
4716
4719 if (!active_cdrs_all) {
4721 }
4723
4725 if (!sched) {
4726 ast_log(LOG_ERROR, "Unable to create schedule context.\n");
4728 }
4729
4732
4734}
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:2872
static int process_config(int reload)
Definition: cdr.c:4476
static void cdr_all_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: cdr.c:4607
static int cdr_all_hash_fn(const void *obj, const int flags)
Definition: cdr.c:986
static int cdr_master_cmp_fn(void *obj, void *arg, int flags)
Definition: cdr.c:952
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:2525
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:2387
static void handle_bridge_enter_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cdr.c:2830
static void handle_cdr_sync_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for a synchronization message.
Definition: cdr.c:2940
static void cdr_master_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: cdr.c:4582
static int cdr_all_cmp_fn(void *obj, void *arg, int flags)
Definition: cdr.c:1010
static void handle_dial_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for Stasis-Core dial messages.
Definition: cdr.c:2201
static void cdr_engine_shutdown(void)
Definition: cdr.c:4524
static int cdr_master_hash_fn(const void *obj, const int flags)
Definition: cdr.c:928
#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:644
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
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
Definition: taskprocessor.h:64

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 396 of file cdr.c.

397{
398 struct module_config *mod_cfg;
400
401 mod_cfg = ao2_alloc(sizeof(*mod_cfg), module_config_destructor);
402 if (!mod_cfg) {
403 return NULL;
404 }
405
406 cdr_config = ao2_alloc(sizeof(*cdr_config), NULL);
407 if (!cdr_config) {
408 ao2_ref(cdr_config, -1);
409 return NULL;
410 }
411 mod_cfg->general = cdr_config;
412
413 return mod_cfg;
414}
static void module_config_destructor(void *obj)
Dispose of a module config object.
Definition: cdr.c:385
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 385 of file cdr.c.

386{
387 struct module_config *cfg = obj;
388
389 if (!cfg) {
390 return;
391 }
392 ao2_ref(cfg->general, -1);
393}

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 372 of file cdr.c.

373{
374 struct module_config *mod_cfg;
375
376 mod_cfg = ao2_global_obj_ref(module_configs);
377 if (!mod_cfg) {
378 return;
379 }
380 cdr_set_debug_mode(mod_cfg);
381 ao2_cleanup(mod_cfg);
382}

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

Definition at line 2129 of file cdr.c.

2130{
2131 if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)) {
2132 return 1;
2133 }
2135
2136 return 0;
2137}

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

◆ post_cdr()

static void post_cdr ( struct ast_cdr cdr)
static

Definition at line 3641 of file cdr.c.

3642{
3643 struct module_config *mod_cfg;
3644 struct cdr_beitem *i;
3645
3646 mod_cfg = ao2_global_obj_ref(module_configs);
3647 if (!mod_cfg) {
3648 return;
3649 }
3650
3651 for (; cdr ; cdr = cdr->next) {
3652 /* For people, who don't want to see unanswered single-channel events */
3653 if (!ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) &&
3656 ast_debug(1, "Skipping CDR for %s since we weren't answered\n", cdr->channel);
3657 continue;
3658 }
3659
3660 /* Modify CDR's */
3662 AST_RWLIST_TRAVERSE(&mo_list, i, list) {
3663 i->be(cdr);
3664 }
3666
3668 continue;
3669 }
3671 AST_RWLIST_TRAVERSE(&be_list, i, list) {
3672 if (!i->suspended) {
3673 i->be(cdr);
3674 }
3675 }
3677 }
3678 ao2_cleanup(mod_cfg);
3679}
@ AST_CDR_FLAG_DISABLE
Definition: cdr.h:244

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, ast_cdr::next, and ast_cdr_config::settings.

Referenced by cdr_detach(), and do_batch_backend_process().

◆ process_config()

static int process_config ( int  reload)
static

Definition at line 4476 of file cdr.c.

4477{
4478 if (!reload) {
4479 if (aco_info_init(&cfg_info)) {
4480 return 1;
4481 }
4482
4497 }
4498
4499 if (aco_process_config(&cfg_info, reload) == ACO_PROCESS_ERROR) {
4500 struct module_config *mod_cfg;
4501
4502 if (reload) {
4503 return 1;
4504 }
4505
4506 /* If we couldn't process the configuration and this wasn't a reload,
4507 * create a default config
4508 */
4509 mod_cfg = module_config_alloc();
4510 if (!mod_cfg
4511 || aco_set_defaults(&general_option, "general", mod_cfg->general)) {
4512 ao2_cleanup(mod_cfg);
4513 return 1;
4514 }
4515 ast_log(LOG_NOTICE, "Failed to process CDR configuration; using defaults\n");
4516 ao2_global_obj_replace_unref(module_configs, mod_cfg);
4517 cdr_set_debug_mode(mod_cfg);
4518 ao2_cleanup(mod_cfg);
4519 }
4520
4521 return 0;
4522}
#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:291
#define MAX_BATCH_SIZE
Definition: cdr.c:292
#define DEFAULT_BATCHMODE
Definition: cdr.c:282
#define DEFAULT_IGNORE_STATE_CHANGES
Definition: cdr.c:288
#define DEFAULT_UNANSWERED
Definition: cdr.c:283
static struct aco_type general_option
The type definition for general options.
Definition: cdr.c:326
#define MAX_BATCH_TIME
Definition: cdr.c:294
static struct aco_type * general_options[]
Definition: cdr.c:370
#define DEFAULT_INITIATED_SECONDS
Definition: cdr.c:286
#define DEFAULT_IGNORE_DIAL_CHANGES
Definition: cdr.c:289
#define DEFAULT_BATCH_SAFE_SHUTDOWN
Definition: cdr.c:296
#define DEFAULT_BATCH_TIME
Definition: cdr.c:293
#define DEFAULT_BATCH_SCHEDULER_ONLY
Definition: cdr.c:295
#define DEFAULT_CHANNEL_ENABLED
Definition: cdr.c:287
#define DEFAULT_ENABLED
Definition: cdr.c:281
static void * module_config_alloc(void)
Create a new module config object.
Definition: cdr.c:396
#define DEFAULT_END_BEFORE_H_EXTEN
Definition: cdr.c:285
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_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 4776 of file cdr.c.

4777{
4778 struct module_config *old_mod_cfg;
4779 struct module_config *mod_cfg;
4780
4781 old_mod_cfg = ao2_global_obj_ref(module_configs);
4782
4783 if (!old_mod_cfg || process_config(1)) {
4784 ao2_cleanup(old_mod_cfg);
4785 return -1;
4786 }
4787
4788 mod_cfg = ao2_global_obj_ref(module_configs);
4789 if (!mod_cfg
4790 || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)
4791 || !ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4792 /* If batch mode used to be enabled, finalize the batch */
4793 if (ast_test_flag(&old_mod_cfg->general->settings, CDR_BATCHMODE)) {
4795 }
4796 }
4797 ao2_cleanup(mod_cfg);
4798
4799 ao2_cleanup(old_mod_cfg);
4801}

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 3863 of file cdr.c.

3864{
3865 batch->size = 0;
3866 batch->head = NULL;
3867 batch->tail = NULL;
3868}

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 1357 of file cdr.c.

1358{
1359 struct ast_var_t *newvariable;
1360
1361 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1362 if (!strcasecmp(ast_var_name(newvariable), name)) {
1364 ast_var_delete(newvariable);
1365 break;
1366 }
1367 }
1369
1370 if (value && (newvariable = ast_var_assign(name, value))) {
1371 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1372 }
1373}
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557

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 1789 of file cdr.c.

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

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 1736 of file cdr.c.

1737{
1738 cdr->start = cdr->lastevent;
1740}

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 1833 of file cdr.c.

1834{
1835 struct ao2_iterator it_cdrs;
1836 char *channel_id;
1837 int success = 0;
1838
1839 ast_string_field_set(cdr, bridge, bridge->uniqueid);
1840
1841 if (ao2_container_count(bridge->channels) == 1) {
1842 /* No one in the bridge yet but us! */
1845 }
1846
1847 for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
1848 !success && (channel_id = ao2_iterator_next(&it_cdrs));
1849 ao2_ref(channel_id, -1)) {
1850 struct cdr_object *cand_cdr_master;
1851 struct cdr_object *cand_cdr;
1852
1853 cand_cdr_master = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
1854 if (!cand_cdr_master) {
1855 continue;
1856 }
1857
1858 ao2_lock(cand_cdr_master);
1859 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
1860 /* Skip any records that are not in a bridge or in this bridge.
1861 * I'm not sure how that would happen, but it pays to be careful. */
1862 if (cand_cdr->fn_table != &bridge_state_fn_table ||
1863 strcmp(cdr->bridge, cand_cdr->bridge)) {
1864 continue;
1865 }
1866
1867 if (single_state_bridge_enter_comparison(cdr, cand_cdr)) {
1868 continue;
1869 }
1870 /* We successfully got a party B - break out */
1871 success = 1;
1872 break;
1873 }
1874 ao2_unlock(cand_cdr_master);
1875 ao2_cleanup(cand_cdr_master);
1876 }
1877 ao2_iterator_destroy(&it_cdrs);
1878
1879 /* We always transition state, even if we didn't get a peer */
1881
1882 /* Success implies that we have a Party B */
1883 if (success) {
1885 }
1886
1888}
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:1789

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, cdr_object::fn_table, cdr_object::next, OBJ_SEARCH_KEY, single_state_bridge_enter_comparison(), 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 1750 of file cdr.c.

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

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, and cdr_object_snapshot::snapshot.

◆ 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 1890 of file cdr.c.

1891{
1893 return 0;
1894}

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 1742 of file cdr.c.

1743{
1744 /* This should never happen! */
1746 ast_assert(0);
1747 return;
1748}

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 1243 of file cdr.c.

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

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 1274 of file cdr.c.

1275{
1276 return (ast_test_flag(&snapshot->flags, AST_FLAG_OUTGOING)
1277 && !(ast_test_flag(&snapshot->flags, AST_FLAG_ORIGINATED)));
1278}
@ 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 3958 of file cdr.c.

3959{
3960 /* Prevent two deletes from happening at the same time */
3962 /* this is okay since we are not being called from within the scheduler */
3964 /* schedule the submission to occur ASAP (1 ms) */
3967
3968 /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
3972}
static int submit_scheduled_batch(const void *data)
Definition: cdr.c:3937
static ast_mutex_t cdr_sched_lock
Definition: cdr.c:450
#define ast_cond_signal(cond)
Definition: lock.h:207
#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 3937 of file cdr.c.

3938{
3939 struct module_config *mod_cfg;
3940 int nextms;
3941
3943
3944 mod_cfg = ao2_global_obj_ref(module_configs);
3945 if (!mod_cfg) {
3946 return 0;
3947 }
3948
3949 /* Calculate the next scheduled interval */
3950 nextms = mod_cfg->general->batch_settings.time * 1000;
3951
3952 ao2_cleanup(mod_cfg);
3953
3954 return nextms;
3955}

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 4650 of file cdr.c.

4651{
4653
4654 return 0;
4655}

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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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 4810 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 464 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 4810 of file cdr.c.

◆ batch

struct cdr_batch * batch = NULL
static

◆ be_list

struct be_list be_list = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
static

◆ 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 755 of file cdr.c.

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 470 of file cdr.c.

Referenced by create_subscriptions(), and destroy_subscriptions().

◆ cdr_batch_lock

ast_mutex_t cdr_batch_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Lock protecting modifications to the batch queue.

Definition at line 454 of file cdr.c.

Referenced by cdr_detach(), and cdr_submit_batch().

◆ cdr_debug_enabled

int cdr_debug_enabled
static

Definition at line 303 of file cdr.c.

◆ cdr_pending_cond

ast_cond_t cdr_pending_cond
static

Definition at line 458 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 = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

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

Definition at line 457 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 3278 of file cdr.c.

Referenced by ast_cdr_serialize_variables(), and ast_cdr_setvar().

◆ cdr_sched

int cdr_sched = -1
static

Definition at line 449 of file cdr.c.

Referenced by handle_cli_status(), and start_batch_mode().

◆ cdr_sched_lock

ast_mutex_t cdr_sched_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Definition at line 450 of file cdr.c.

Referenced by start_batch_mode().

◆ cdr_thread

pthread_t cdr_thread = AST_PTHREADT_NULL
static

Definition at line 451 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 479 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 473 of file cdr.c.

Referenced by create_subscriptions(), and destroy_subscriptions().

◆ cli_commands

struct ast_cli_entry cli_commands[]
static

Definition at line 4385 of file cdr.c.

Referenced by cdr_engine_shutdown(), and load_module().

◆ dial_changes_ignored

int dial_changes_ignored
static

Definition at line 304 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 700 of file cdr.c.

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 733 of file cdr.c.

Referenced by dial_state_process_dial_end().

◆ finalized_state_fn_table

struct cdr_object_fn_table finalized_state_fn_table

◆ general_option

struct aco_type general_option
static

The type definition for general options.

Definition at line 326 of file cdr.c.

Referenced by process_config().

◆ general_options

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

Definition at line 370 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 445 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 335 of file cdr.c.

◆ ignore_option

struct aco_type ignore_option
static

Definition at line 348 of file cdr.c.

◆ mo_list

struct mo_list mo_list = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
static

◆ module_file_conf

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

The file definition.

Definition at line 360 of file cdr.c.

◆ 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 774 of file cdr.c.

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 476 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 448 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 669 of file cdr.c.

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 467 of file cdr.c.

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