Asterisk - The Open Source Telephony Project GIT-master-f36a736
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 subcriptions 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:249

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

Definition at line 244 of file cdr.c.

◆ DEFAULT_BATCH_SAFE_SHUTDOWN

#define DEFAULT_BATCH_SAFE_SHUTDOWN   "1"

Definition at line 242 of file cdr.c.

◆ DEFAULT_BATCH_SCHEDULER_ONLY

#define DEFAULT_BATCH_SCHEDULER_ONLY   "0"

Definition at line 241 of file cdr.c.

◆ DEFAULT_BATCH_SIZE

#define DEFAULT_BATCH_SIZE   "100"

Definition at line 237 of file cdr.c.

◆ DEFAULT_BATCH_TIME

#define DEFAULT_BATCH_TIME   "300"

Definition at line 239 of file cdr.c.

◆ DEFAULT_BATCHMODE

#define DEFAULT_BATCHMODE   "0"

Definition at line 228 of file cdr.c.

◆ DEFAULT_CHANNEL_ENABLED

#define DEFAULT_CHANNEL_ENABLED   "1"

Definition at line 233 of file cdr.c.

◆ DEFAULT_CONGESTION

#define DEFAULT_CONGESTION   "0"

Definition at line 230 of file cdr.c.

◆ DEFAULT_ENABLED

#define DEFAULT_ENABLED   "1"

Definition at line 227 of file cdr.c.

◆ DEFAULT_END_BEFORE_H_EXTEN

#define DEFAULT_END_BEFORE_H_EXTEN   "1"

Definition at line 231 of file cdr.c.

◆ DEFAULT_IGNORE_DIAL_CHANGES

#define DEFAULT_IGNORE_DIAL_CHANGES   "0"

Definition at line 235 of file cdr.c.

◆ DEFAULT_IGNORE_STATE_CHANGES

#define DEFAULT_IGNORE_STATE_CHANGES   "0"

Definition at line 234 of file cdr.c.

◆ DEFAULT_INITIATED_SECONDS

#define DEFAULT_INITIATED_SECONDS   "0"

Definition at line 232 of file cdr.c.

◆ DEFAULT_UNANSWERED

#define DEFAULT_UNANSWERED   "0"

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

◆ MAX_BATCH_TIME

#define MAX_BATCH_TIME   86400

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

433 {
434 /*!
435 * The CDR was the only party in the bridge.
436 */
438 /*!
439 * The CDR was able to obtain a Party B from some other party already in the bridge
440 */
442 /*!
443 * The CDR was not able to obtain a Party B
444 */
446 /*!
447 * This CDR can't handle a bridge enter message and a new CDR needs to be created
448 */
450};
@ BRIDGE_ENTER_ONLY_PARTY
Definition: cdr.c:437
@ BRIDGE_ENTER_NO_PARTY_B
Definition: cdr.c:445
@ BRIDGE_ENTER_NEED_CDR
Definition: cdr.c:449
@ BRIDGE_ENTER_OBTAINED_PARTY_B
Definition: cdr.c:441

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 4756 of file cdr.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

3502{
3503 struct ast_cdr *x;
3504
3505 x = ast_calloc(1, sizeof(*x));
3506 return x;
3507}
#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 2932 of file cdr.c.

2933{
2934 int success = -1;
2935 struct cdr_beitem *i = NULL;
2936
2938 AST_RWLIST_TRAVERSE(&be_list, i, list) {
2939 if (!strcasecmp(name, i->name)) {
2940 ast_debug(3, "Suspending CDR backend %s\n", i->name);
2941 i->suspended = 1;
2942 success = 0;
2943 }
2944 }
2946
2947 return success;
2948}
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:372
Registration object for CDR backends.
Definition: cdr.c:363
char name[20]
Definition: cdr.c:364

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

2951{
2952 int success = -1;
2953 struct cdr_beitem *i = NULL;
2954
2956 AST_RWLIST_TRAVERSE(&be_list, i, list) {
2957 if (!strcasecmp(name, i->name)) {
2958 ast_debug(3, "Unsuspending CDR backend %s\n", i->name);
2959 i->suspended = 0;
2960 success = 0;
2961 }
2962 }
2964
2965 return success;
2966}

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

3655{
3656 struct cdr_object *cdr;
3657 struct cdr_object *it_cdr;
3658
3659 cdr = cdr_object_get_by_name(channel_name);
3660 if (!cdr) {
3661 return -1;
3662 }
3663
3664 ao2_lock(cdr);
3665 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3666 if (it_cdr->fn_table == &finalized_state_fn_table) {
3667 continue;
3668 }
3669 ast_clear_flag(&it_cdr->flags, option);
3670 }
3671 ao2_unlock(cdr);
3672
3673 ao2_cleanup(cdr);
3674 return 0;
3675}
#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:736
static struct cdr_object * cdr_object_get_by_name(const char *name)
Definition: cdr.c:3391
An in-memory representation of an active CDR.
Definition: cdr.c:754
struct cdr_object_fn_table * fn_table
Definition: cdr.c:757
struct cdr_object * next
Definition: cdr.c:778
struct ast_flags flags
Definition: cdr.c:765
#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 3509 of file cdr.c.

3510{
3511 switch (disposition) {
3512 case AST_CDR_NULL:
3513 return "NO ANSWER"; /* by default, for backward compatibility */
3514 case AST_CDR_NOANSWER:
3515 return "NO ANSWER";
3516 case AST_CDR_FAILED:
3517 return "FAILED";
3518 case AST_CDR_BUSY:
3519 return "BUSY";
3520 case AST_CDR_ANSWERED:
3521 return "ANSWERED";
3522 case AST_CDR_CONGESTION:
3523 return "CONGESTION";
3524 }
3525 return "UNKNOWN";
3526}
@ 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 3064 of file cdr.c.

3065{
3066 struct ast_cdr *newcdr;
3067
3068 if (!cdr) {
3069 return NULL;
3070 }
3071 newcdr = ast_cdr_alloc();
3072 if (!newcdr) {
3073 return NULL;
3074 }
3075
3076 *newcdr = *cdr;
3078 copy_variables(&newcdr->varshead, &cdr->varshead);
3079 newcdr->next = NULL;
3080
3081 return newcdr;
3082}
struct ast_cdr * ast_cdr_alloc(void)
Allocate a CDR record.
Definition: cdr.c:3501
static int copy_variables(struct varshead *to_list, struct varshead *from_list)
Copy variables from one list to another.
Definition: cdr.c:789
#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 4682 of file cdr.c.

4683{
4684 RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
4685
4686 /* Since this is called explicitly during process shutdown, we might not have ever
4687 * been initialized. If so, the config object will be NULL.
4688 */
4689 if (!mod_cfg) {
4690 return;
4691 }
4692
4693 if (cdr_sync_message_type()) {
4694 void *payload;
4695 struct stasis_message *message;
4696
4697 if (!stasis_router) {
4698 return;
4699 }
4700
4701 /* Make sure we have the needed items */
4702 payload = ao2_alloc(sizeof(*payload), NULL);
4703 if (!payload) {
4704 return;
4705 }
4706
4707 ast_debug(1, "CDR Engine termination request received; waiting on messages...\n");
4708
4709 message = stasis_message_create(cdr_sync_message_type(), payload);
4710 if (message) {
4712 }
4714 ao2_cleanup(payload);
4715 }
4716
4717 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4718 cdr_submit_batch(ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN));
4719 }
4720}
#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:413
static void cdr_submit_batch(int shutdown)
Definition: cdr.c:3845
@ 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:264
#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 3716 of file cdr.c.

3717{
3718 RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
3719 struct cdr_object *new_cdr;
3720 struct cdr_object *it_cdr;
3721 struct cdr_object *cdr_obj;
3722
3723 if (!cdr) {
3724 return -1;
3725 }
3726
3727 {
3728 SCOPED_AO2LOCK(lock, cdr);
3729 struct timeval now = ast_tvnow();
3730
3731 cdr_obj = cdr->last;
3732 if (cdr_obj->fn_table == &finalized_state_fn_table) {
3733 /* If the last CDR in the chain is finalized, don't allow a fork -
3734 * things are already dying at this point
3735 */
3736 return -1;
3737 }
3738
3739 /* Copy over the basic CDR information. The Party A information is
3740 * copied over automatically as part of the append
3741 */
3742 ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
3743 new_cdr = cdr_object_create_and_append(cdr, &now);
3744 if (!new_cdr) {
3745 return -1;
3746 }
3747 new_cdr->fn_table = cdr_obj->fn_table;
3748 ast_string_field_set(new_cdr, bridge, cdr->bridge);
3749 ast_string_field_set(new_cdr, appl, cdr->appl);
3750 ast_string_field_set(new_cdr, data, cdr->data);
3751 ast_string_field_set(new_cdr, context, cdr->context);
3752 ast_string_field_set(new_cdr, exten, cdr->exten);
3753 new_cdr->flags = cdr->flags;
3754 /* Explicitly clear the AST_CDR_LOCK_APP flag - we want
3755 * the application to be changed on the new CDR if the
3756 * dialplan demands it
3757 */
3759
3760 /* If there's a Party B, copy it over as well */
3761 if (cdr_obj->party_b.snapshot) {
3762 new_cdr->party_b.snapshot = cdr_obj->party_b.snapshot;
3763 ao2_ref(new_cdr->party_b.snapshot, +1);
3764 cdr_all_relink(new_cdr);
3765 strcpy(new_cdr->party_b.userfield, cdr_obj->party_b.userfield);
3766 new_cdr->party_b.flags = cdr_obj->party_b.flags;
3768 copy_variables(&new_cdr->party_b.variables, &cdr_obj->party_b.variables);
3769 }
3770 }
3771 new_cdr->start = cdr_obj->start;
3772 new_cdr->answer = cdr_obj->answer;
3773 new_cdr->lastevent = ast_tvnow();
3774
3775 /* Modify the times based on the flags passed in */
3777 && new_cdr->party_a.snapshot->state == AST_STATE_UP) {
3778 new_cdr->answer = ast_tvnow();
3779 }
3781 new_cdr->answer = ast_tvnow();
3782 new_cdr->start = ast_tvnow();
3783 }
3784
3785 /* Create and append, by default, copies over the variables */
3787 free_variables(&new_cdr->party_a.variables);
3788 }
3789
3790 /* Finalize any current CDRs */
3792 for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->next) {
3793 if (it_cdr->fn_table == &finalized_state_fn_table) {
3794 continue;
3795 }
3796 /* Force finalization on the CDR. This will bypass any checks for
3797 * end before 'h' extension.
3798 */
3799 cdr_object_finalize(it_cdr);
3801 }
3802 }
3803 }
3804
3805 return 0;
3806}
ast_mutex_t lock
Definition: app_sla.c:331
#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:1118
static void cdr_object_finalize(struct cdr_object *cdr)
Finalize a CDR.
Definition: cdr.c:1483
static void cdr_all_relink(struct cdr_object *cdr)
Definition: cdr.c:991
static void free_variables(struct varshead *headp)
Delete all variables from a variable list.
Definition: cdr.c:820
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:865
@ 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:604
#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:748
struct varshead variables
Definition: cdr.c:750
struct ast_channel_snapshot * snapshot
Definition: cdr.c:747
unsigned int flags
Definition: cdr.c:749
struct timeval answer
Definition: cdr.c:761
struct cdr_object_snapshot party_a
Definition: cdr.c:755
struct timeval lastevent
Definition: cdr.c:763
struct cdr_object * last
Definition: cdr.c:779
struct timeval start
Definition: cdr.c:760
struct cdr_object_snapshot party_b
Definition: cdr.c:756
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 3116 of file cdr.c.

3117{
3118 const char *fmt = "%Y-%m-%d %T";
3119 const char *varbuf;
3120
3121 if (!cdr) {
3122 return;
3123 }
3124
3125 *ret = NULL;
3126
3127 if (!strcasecmp(name, "clid")) {
3128 ast_copy_string(workspace, cdr->clid, workspacelen);
3129 } else if (!strcasecmp(name, "src")) {
3130 ast_copy_string(workspace, cdr->src, workspacelen);
3131 } else if (!strcasecmp(name, "dst")) {
3132 ast_copy_string(workspace, cdr->dst, workspacelen);
3133 } else if (!strcasecmp(name, "dcontext")) {
3134 ast_copy_string(workspace, cdr->dcontext, workspacelen);
3135 } else if (!strcasecmp(name, "channel")) {
3136 ast_copy_string(workspace, cdr->channel, workspacelen);
3137 } else if (!strcasecmp(name, "dstchannel")) {
3138 ast_copy_string(workspace, cdr->dstchannel, workspacelen);
3139 } else if (!strcasecmp(name, "lastapp")) {
3140 ast_copy_string(workspace, cdr->lastapp, workspacelen);
3141 } else if (!strcasecmp(name, "lastdata")) {
3142 ast_copy_string(workspace, cdr->lastdata, workspacelen);
3143 } else if (!strcasecmp(name, "start")) {
3144 cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
3145 } else if (!strcasecmp(name, "answer")) {
3146 cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
3147 } else if (!strcasecmp(name, "end")) {
3148 cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
3149 } else if (!strcasecmp(name, "duration")) {
3150 snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
3151 } else if (!strcasecmp(name, "billsec")) {
3152 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);
3153 } else if (!strcasecmp(name, "disposition")) {
3154 if (raw) {
3155 snprintf(workspace, workspacelen, "%ld", cdr->disposition);
3156 } else {
3157 ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
3158 }
3159 } else if (!strcasecmp(name, "amaflags")) {
3160 if (raw) {
3161 snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
3162 } else {
3163 ast_copy_string(workspace, ast_channel_amaflags2string(cdr->amaflags), workspacelen);
3164 }
3165 } else if (!strcasecmp(name, "accountcode")) {
3166 ast_copy_string(workspace, cdr->accountcode, workspacelen);
3167 } else if (!strcasecmp(name, "peeraccount")) {
3168 ast_copy_string(workspace, cdr->peeraccount, workspacelen);
3169 } else if (!strcasecmp(name, "uniqueid")) {
3170 ast_copy_string(workspace, cdr->uniqueid, workspacelen);
3171 } else if (!strcasecmp(name, "linkedid")) {
3172 ast_copy_string(workspace, cdr->linkedid, workspacelen);
3173 } else if (!strcasecmp(name, "tenantid")) {
3174 ast_copy_string(workspace, cdr->tenantid, workspacelen);
3175 } else if (!strcasecmp(name, "peertenantid")) {
3176 ast_copy_string(workspace, cdr->peertenantid, workspacelen);
3177 } else if (!strcasecmp(name, "userfield")) {
3178 ast_copy_string(workspace, cdr->userfield, workspacelen);
3179 } else if (!strcasecmp(name, "sequence")) {
3180 snprintf(workspace, workspacelen, "%d", cdr->sequence);
3181 } else if ((varbuf = cdr_format_var_internal(cdr, name))) {
3182 ast_copy_string(workspace, varbuf, workspacelen);
3183 } else {
3184 workspace[0] = '\0';
3185 }
3186
3187 if (!ast_strlen_zero(workspace)) {
3188 *ret = workspace;
3189 }
3190}
static void cdr_get_tv(struct timeval when, const char *fmt, char *buf, int bufsize)
Definition: cdr.c:3101
static const char * cdr_format_var_internal(struct ast_cdr *cdr, const char *name)
Definition: cdr.c:3084
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3509
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4392
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 3490 of file cdr.c.

3491{
3492 while (cdr) {
3493 struct ast_cdr *next = cdr->next;
3494
3495 free_variables(&cdr->varshead);
3496 ast_free(cdr);
3497 cdr = next;
3498 }
3499}
#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 3019 of file cdr.c.

3020{
3021 struct cdr_beitem *match = NULL;
3022 int active_count;
3023
3024 AST_RWLIST_WRLOCK(generic_list);
3025 AST_RWLIST_TRAVERSE(generic_list, match, list) {
3026 if (!strcasecmp(name, match->name)) {
3027 break;
3028 }
3029 }
3030
3031 if (!match) {
3032 AST_RWLIST_UNLOCK(generic_list);
3033 return 0;
3034 }
3035
3037
3038 if (!match->suspended && active_count != 0) {
3039 AST_RWLIST_UNLOCK(generic_list);
3040 ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
3041 name, active_count);
3042 return -1;
3043 }
3044
3045 AST_RWLIST_REMOVE(generic_list, match, list);
3046 AST_RWLIST_UNLOCK(generic_list);
3047
3048 ast_verb(5, "Unregistered '%s' CDR backend\n", name);
3049 ast_free(match);
3050
3051 return 0;
3052}
#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:407
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:2362
#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 2892 of file cdr.c.

2893{
2894 struct ast_cdr_config *general;
2895 struct module_config *mod_cfg;
2896
2897 mod_cfg = ao2_global_obj_ref(module_configs);
2898 if (!mod_cfg) {
2899 return NULL;
2900 }
2901 general = ao2_bump(mod_cfg->general);
2902 ao2_cleanup(mod_cfg);
2903 return general;
2904}
#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:265

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

3404{
3405 struct cdr_object *cdr;
3406 struct cdr_object *cdr_obj;
3407
3408 if (ast_strlen_zero(name)) {
3409 return 1;
3410 }
3411
3412 cdr = cdr_object_get_by_name(channel_name);
3413 if (!cdr) {
3414 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3415 return 1;
3416 }
3417
3418 ao2_lock(cdr);
3419
3420 cdr_obj = cdr->last;
3421 if (cdr_object_format_property(cdr_obj, name, value, length)) {
3422 /* Property failed; attempt variable */
3423 cdr_object_format_var_internal(cdr_obj, name, value, length);
3424 }
3425
3426 ao2_unlock(cdr);
3427
3428 ao2_cleanup(cdr);
3429 return 0;
3430}
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:3314
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:3297
#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 2927 of file cdr.c.

2928{
2930}
static int is_cdr_flag_set(unsigned int cdr_flag)
Definition: cdr.c:1168
@ 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 4373 of file cdr.c.

4374{
4375 if (!stasis_router) {
4376 return NULL;
4377 }
4378
4380 return stasis_router;
4381}

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

3015{
3016 return cdr_generic_register((struct be_list *)&mo_list, name, desc, be);
3017}
static int cdr_generic_register(struct be_list *generic_list, const char *name, const char *desc, ast_cdrbe be)
Definition: cdr.c:2968
static const char desc[]
Definition: cdr_radius.c:84
char * be
Definition: eagi_proxy.c:73
List of registered modifiers.
Definition: cdr.c:375

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

3060{
3061 return ast_cdr_generic_unregister((struct be_list *)&mo_list, name);
3062}
static int ast_cdr_generic_unregister(struct be_list *generic_list, const char *name)
Definition: cdr.c:3019

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

3010{
3012}

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

3678{
3679 struct cdr_object *cdr;
3680 struct ast_var_t *vardata;
3681 struct cdr_object *it_cdr;
3682
3683 cdr = cdr_object_get_by_name(channel_name);
3684 if (!cdr) {
3685 return -1;
3686 }
3687
3688 ao2_lock(cdr);
3689 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3690 /* clear variables */
3691 if (!keep_variables) {
3692 while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_a.variables, entries))) {
3693 ast_var_delete(vardata);
3694 }
3695 if (cdr->party_b.snapshot) {
3696 while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_b.variables, entries))) {
3697 ast_var_delete(vardata);
3698 }
3699 }
3700 }
3701
3702 /* Reset to initial state */
3703 memset(&it_cdr->start, 0, sizeof(it_cdr->start));
3704 memset(&it_cdr->end, 0, sizeof(it_cdr->end));
3705 memset(&it_cdr->answer, 0, sizeof(it_cdr->answer));
3706 it_cdr->start = ast_tvnow();
3707 it_cdr->lastevent = it_cdr->start;
3709 }
3710 ao2_unlock(cdr);
3711
3712 ao2_cleanup(cdr);
3713 return 0;
3714}
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:1537
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:762

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

3433{
3434 struct cdr_object *cdr;
3435 struct cdr_object *it_cdr;
3436 struct ast_var_t *variable;
3437 const char *var;
3438 char workspace[256];
3439 int total = 0, x = 0, i;
3440
3441 cdr = cdr_object_get_by_name(channel_name);
3442 if (!cdr) {
3444 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3445 }
3446 return 0;
3447 }
3448
3450
3451 ao2_lock(cdr);
3452 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3453 if (++x > 1) {
3454 ast_str_append(buf, 0, "\n");
3455 }
3456
3457 AST_LIST_TRAVERSE(&it_cdr->party_a.variables, variable, entries) {
3458 if (!(var = ast_var_name(variable))) {
3459 continue;
3460 }
3461
3462 if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variable), ""), sep) < 0) {
3463 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3464 break;
3465 }
3466
3467 total++;
3468 }
3469
3470 for (i = 0; cdr_readonly_vars[i]; i++) {
3471 if (cdr_object_format_property(it_cdr, cdr_readonly_vars[i], workspace, sizeof(workspace))) {
3472 /* Unhandled read-only CDR variable. */
3473 ast_assert(0);
3474 continue;
3475 }
3476
3477 if (!ast_strlen_zero(workspace)
3478 && ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, workspace, sep) < 0) {
3479 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3480 break;
3481 }
3482 total++;
3483 }
3484 }
3485 ao2_unlock(cdr);
3486 ao2_cleanup(cdr);
3487 return total;
3488}
#define var
Definition: ast_expr2f.c:605
static const char *const cdr_readonly_vars[]
Definition: cdr.c:3224
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::@211 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 2906 of file cdr.c.

2907{
2908 struct module_config *mod_cfg;
2909
2910 if (!config) {
2911 return;
2912 }
2913
2914 mod_cfg = ao2_global_obj_ref(module_configs);
2915 if (!mod_cfg) {
2916 return;
2917 }
2918
2919 ao2_replace(mod_cfg->general, config);
2920
2921 cdr_set_debug_mode(mod_cfg);
2923
2924 ao2_cleanup(mod_cfg);
2925}
#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:244
static int cdr_toggle_runtime_options(void)
Checks if CDRs are enabled and enables/disables the necessary options.
Definition: cdr.c:4569
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 3627 of file cdr.c.

3628{
3629 struct cdr_object *cdr;
3630 struct cdr_object *it_cdr;
3631
3632 cdr = cdr_object_get_by_name(channel_name);
3633 if (!cdr) {
3634 return -1;
3635 }
3636
3637 ao2_lock(cdr);
3638 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3639 if (it_cdr->fn_table == &finalized_state_fn_table) {
3640 continue;
3641 }
3642 /* Note: in general, set the flags on both the CDR record as well as the
3643 * Party A. Sometimes all we have is the Party A to look at.
3644 */
3645 ast_set_flag(&it_cdr->flags, option);
3646 ast_set_flag(&it_cdr->party_a, option);
3647 }
3648 ao2_unlock(cdr);
3649
3650 ao2_cleanup(cdr);
3651 return 0;
3652}
#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 3556 of file cdr.c.

3557{
3558 struct cdr_object *cdr;
3559 struct party_b_userfield_update party_b_info = {
3561 .userfield = userfield,
3562 };
3563 struct cdr_object *it_cdr;
3564
3565 /* Handle Party A */
3566 cdr = cdr_object_get_by_name(channel_name);
3567 if (cdr) {
3568 ao2_lock(cdr);
3569 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3570 if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3571 continue;
3572 }
3573 ast_copy_string(it_cdr->party_a.userfield, userfield,
3574 sizeof(it_cdr->party_a.userfield));
3575 }
3576 ao2_unlock(cdr);
3577 }
3578
3579 /* Handle Party B */
3582 &party_b_info);
3583
3584 ao2_cleanup(cdr);
3585}
#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:3534
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:410
const char * userfield
Definition: cdr.c:3530
const char * channel_name
Definition: cdr.c:3529

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

3250{
3251 struct cdr_object *cdr;
3252 struct cdr_object *it_cdr;
3253 struct ao2_iterator *it_cdrs;
3254 char *arg = ast_strdupa(channel_name);
3255 int x;
3256
3257 for (x = 0; cdr_readonly_vars[x]; x++) {
3258 if (!strcasecmp(name, cdr_readonly_vars[x])) {
3259 ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!\n", name);
3260 return -1;
3261 }
3262 }
3263
3265 if (!it_cdrs) {
3266 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3267 return -1;
3268 }
3269
3270 for (; (cdr = ao2_iterator_next(it_cdrs)); ao2_unlock(cdr), ao2_cleanup(cdr)) {
3271 ao2_lock(cdr);
3272 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3273 struct varshead *headp = NULL;
3274
3275 if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3276 continue;
3277 }
3278 if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->base->name)) {
3279 headp = &it_cdr->party_a.variables;
3280 } else if (it_cdr->party_b.snapshot
3281 && !strcasecmp(channel_name, it_cdr->party_b.snapshot->base->name)) {
3282 headp = &it_cdr->party_b.variables;
3283 }
3284 if (headp) {
3285 set_variable(headp, name, value);
3286 }
3287 }
3288 }
3289 ao2_iterator_destroy(it_cdrs);
3290
3291 return 0;
3292}
#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:3196
static void set_variable(struct varshead *headp, const char *name, const char *value)
Definition: cdr.c:1303
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 3054 of file cdr.c.

3055{
3057}

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

1655{
1656 /* Base process bridge enter simply indicates that we can't handle it */
1657 return BRIDGE_ENTER_NEED_CDR;
1658}

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

1645{
1646 return 0;
1647}

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

1650{
1651 return 0;
1652}

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

1661{
1662 char park_info[128];
1663
1664 ast_assert(!strcasecmp(parking_info->parkee->base->name, cdr->party_a.snapshot->base->name));
1665
1666 /* Update Party A information regardless */
1667 cdr->fn_table->process_party_a(cdr, parking_info->parkee);
1668
1669 /* Fake out where we're parked */
1670 ast_string_field_set(cdr, appl, "Park");
1671 snprintf(park_info, sizeof(park_info), "%s:%u", parking_info->parkinglot, parking_info->parkingspace);
1672 ast_string_field_set(cdr, data, park_info);
1673
1674 /* Prevent any further changes to the App/Data fields for this record */
1676
1677 return 0;
1678}
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:479

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

1584{
1585 ast_assert(strcasecmp(snapshot->base->name, cdr->party_a.snapshot->base->name) == 0);
1586
1587 /* Finalize the CDR if we're in hangup logic and we're set to do so */
1591 return 0;
1592 }
1593
1594 /*
1595 * Only record the context and extension if we aren't in a subroutine, or if
1596 * we are executing hangup logic.
1597 */
1600 if (strcmp(cdr->context, snapshot->dialplan->context)) {
1601 ast_string_field_set(cdr, context, snapshot->dialplan->context);
1602 }
1603 if (strcmp(cdr->exten, snapshot->dialplan->exten)) {
1604 ast_string_field_set(cdr, exten, snapshot->dialplan->exten);
1605 }
1606 }
1607
1608 cdr_object_swap_snapshot(&cdr->party_a, snapshot);
1609
1610 /* When Party A is originated to an application and the application exits, the stack
1611 * will attempt to clear the application and restore the dummy originate application
1612 * of "AppDialX". Prevent that, and any other application changes we might not want
1613 * here.
1614 */
1616 && !ast_strlen_zero(snapshot->dialplan->appl)
1617 && (strncasecmp(snapshot->dialplan->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
1618 if (strcmp(cdr->appl, snapshot->dialplan->appl)) {
1619 ast_string_field_set(cdr, appl, snapshot->dialplan->appl);
1620 }
1621 if (strcmp(cdr->data, snapshot->dialplan->data)) {
1622 ast_string_field_set(cdr, data, snapshot->dialplan->data);
1623 }
1624
1625 /* Dial (app_dial) is a special case. Because pre-dial handlers, which
1626 * execute before the dial begins, will alter the application/data to
1627 * something people typically don't want to see, if we see a channel enter
1628 * into Dial here, we set the appl/data accordingly and lock it.
1629 */
1630 if (!strcmp(snapshot->dialplan->appl, "Dial")) {
1632 }
1633 }
1634
1635 if (strcmp(cdr->linkedid, snapshot->peer->linkedid)) {
1636 ast_string_field_set(cdr, linkedid, snapshot->peer->linkedid);
1637 }
1640
1641 return 0;
1642}
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:1574
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:1520
@ CDR_END_BEFORE_H_EXTEN
Definition: cdr.h:224
@ AST_SOFTHANGUP_HANGUP_EXEC
Definition: channel.h:1174
@ AST_FLAG_SUBROUTINE_EXEC
Definition: channel.h:1078
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:777
const ast_string_field data
Definition: cdr.c:777
const ast_string_field context
Definition: cdr.c:777
const ast_string_field exten
Definition: cdr.c:777
const ast_string_field appl
Definition: cdr.c:777

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

2541{
2542 struct cdr_object *new_cdr;
2543
2544 new_cdr = cdr_object_create_and_append(cdr, &cdr->lastevent);
2545 if (!new_cdr) {
2546 return;
2547 }
2549 cdr_all_relink(new_cdr);
2551 ast_string_field_set(new_cdr, bridge, cdr->bridge);
2553 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2554 new_cdr, new_cdr->party_a.snapshot->base->name,
2556}
struct cdr_object_fn_table bridge_state_fn_table
The virtual table for the Bridged state.
Definition: cdr.c:701
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:834
const ast_string_field bridge
Definition: cdr.c:777

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

2571{
2572 struct cdr_object_snapshot *party_a;
2573 struct cdr_object *cand_cdr;
2574
2575 ao2_lock(base_cand_cdr);
2576
2577 for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->next) {
2578 /* Skip any records that are not in this bridge */
2579 if (strcmp(cand_cdr->bridge, cdr->bridge)) {
2580 continue;
2581 }
2582
2583 /* If the candidate is us or someone we've taken on, pass on by */
2584 if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)
2585 || (cdr->party_b.snapshot
2586 && !strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name))) {
2587 break;
2588 }
2589
2590 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
2591 /* We're party A - make a new CDR, append it to us, and set the candidate as
2592 * Party B */
2593 if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
2594 bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
2595 break;
2596 }
2597
2598 /* We're Party B. Check if we can add ourselves immediately or if we need
2599 * a new CDR for them (they already have a Party B) */
2600 if (cand_cdr->party_b.snapshot
2601 && strcasecmp(cand_cdr->party_b.snapshot->base->name, cdr->party_a.snapshot->base->name)) {
2602 bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a);
2603 } else {
2604 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2605 cand_cdr, cand_cdr->party_a.snapshot->base->name,
2606 cdr->party_a.snapshot->base->name);
2607 cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
2608 cdr_all_relink(cand_cdr);
2609 /* It's possible that this joined at one point and was never chosen
2610 * as party A. Clear their end time, as it would be set in such a
2611 * case.
2612 */
2613 memset(&cand_cdr->end, 0, sizeof(cand_cdr->end));
2614 }
2615
2616 break;
2617 }
2618
2619 ao2_unlock(base_cand_cdr);
2620}
static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, struct cdr_object_snapshot *party_b)
Definition: cdr.c:2539
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:1233
A wrapper object around a snapshot. Fields that are mutable by the CDR engine are replicated here.
Definition: cdr.c:746

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

2059{
2060 if (strcmp(cdr->bridge, bridge->uniqueid)) {
2061 return 1;
2062 }
2063 if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)
2064 && cdr->party_b.snapshot
2065 && strcasecmp(cdr->party_b.snapshot->base->name, channel->base->name)) {
2066 return 1;
2067 }
2069
2070 return 0;
2071}
const ast_string_field uniqueid
Definition: bridge.h:328

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

957{
958 struct cdr_object *left = obj;
959 struct cdr_object *right = arg;
960 const char *right_key = arg;
961 int cmp;
962
963 switch (flags & OBJ_SEARCH_MASK) {
965 right_key = right->party_b_name;
966 /* Fall through */
967 case OBJ_SEARCH_KEY:
968 cmp = strcasecmp(left->party_b_name, right_key);
969 break;
971 /*
972 * We could also use a partial key struct containing a length
973 * so strlen() does not get called for every comparison instead.
974 */
975 cmp = strncasecmp(left->party_b_name, right_key, strlen(right_key));
976 break;
977 default:
978 /* Sort can only work on something with a full or partial key. */
979 ast_assert(0);
980 cmp = 0;
981 break;
982 }
983 return cmp ? 0 : CMP_MATCH;
984}
@ 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:777

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

933{
934 const struct cdr_object *cdr;
935 const char *key;
936
937 switch (flags & OBJ_SEARCH_MASK) {
938 case OBJ_SEARCH_KEY:
939 key = obj;
940 break;
942 cdr = obj;
943 key = cdr->party_b_name;
944 break;
945 default:
946 ast_assert(0);
947 return 0;
948 }
949 return ast_str_case_hash(key);
950}
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 4553 of file cdr.c.

4554{
4555 struct cdr_object *cdr = v_obj;
4556
4557 if (!cdr) {
4558 return;
4559 }
4560 prnt(where, "Party A: %s; Party B: %s; Bridge %s",
4561 cdr->party_a.snapshot->base->name,
4562 cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<unknown>",
4563 cdr->bridge);
4564}

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

992{
994 if (cdr->party_b.snapshot) {
995 if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->base->name)) {
997 ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->base->name);
999 }
1000 } else {
1002 ast_string_field_set(cdr, party_b_name, "");
1003 }
1005}
#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 1012 of file cdr.c.

1013{
1014 struct cdr_object *cur;
1015 struct cdr_object *next;
1016
1017 ast_assert(cdr->is_root);
1018
1019 /* Hold a ref to the root CDR to ensure the list members don't go away on us. */
1020 ao2_ref(cdr, +1);
1022 for (cur = cdr; cur; cur = next) {
1023 next = cur->next;
1025 /*
1026 * It is safe to still use cur after unlinking because the
1027 * root CDR holds a ref to all the CDRs in the list and we
1028 * have a ref to the root CDR.
1029 */
1031 }
1033 ao2_ref(cdr, -1);
1034}
int is_root
Definition: cdr.c:780

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

3921{
3922 struct cdr_batch_item *newtail;
3923 int curr;
3924 RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
3925 int submit_batch = 0;
3926
3927 if (!cdr) {
3928 return;
3929 }
3930
3931 /* maybe they disabled CDR stuff completely, so just drop it */
3932 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
3933 ast_debug(1, "Dropping CDR !\n");
3935 return;
3936 }
3937
3938 /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
3939 if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
3940 post_cdr(cdr);
3942 return;
3943 }
3944
3945 /* otherwise, each CDR gets put into a batch list (at the end) */
3946 ast_debug(1, "CDR detaching from this thread\n");
3947
3948 /* we'll need a new tail for every CDR */
3949 if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
3950 post_cdr(cdr);
3952 return;
3953 }
3954
3955 /* don't traverse a whole list (just keep track of the tail) */
3957 if (!batch)
3958 init_batch();
3959 if (!batch->head) {
3960 /* new batch is empty, so point the head at the new tail */
3961 batch->head = newtail;
3962 } else {
3963 /* already got a batch with something in it, so just append a new tail */
3964 batch->tail->next = newtail;
3965 }
3966 newtail->cdr = cdr;
3967 batch->tail = newtail;
3968 curr = batch->size++;
3969
3970 /* if we have enough stuff to post, then do it */
3971 if (curr >= (mod_cfg->general->batch_settings.size - 1)) {
3972 submit_batch = 1;
3973 }
3975
3976 /* Don't submit a batch with cdr_batch_lock held */
3977 if (submit_batch) {
3979 }
3980}
void ast_cdr_free(struct ast_cdr *cdr)
Free a CDR record.
Definition: cdr.c:3490
static ast_mutex_t cdr_batch_lock
Lock protecting modifications to the batch queue.
Definition: cdr.c:400
static struct cdr_batch * batch
static int init_batch(void)
Definition: cdr.c:3817
static void start_batch_mode(void)
Definition: cdr.c:3904
static void post_cdr(struct ast_cdr *cdr)
Definition: cdr.c:3587
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
Queued CDR waiting to be batched.
Definition: cdr.c:378
struct ast_cdr * cdr
Definition: cdr.c:379
struct cdr_batch_item * next
Definition: cdr.c:380
int size
Definition: cdr.c:385
struct cdr_batch_item * head
Definition: cdr.c:386
struct cdr_batch_item * tail
Definition: cdr.c:387

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

4502{
4503 /* Only create the thread level portions once */
4507 ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
4508 return;
4509 }
4510 }
4511
4512 /* Start the batching process */
4514
4515 ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %u or time %u seconds.\n",
4516 config->batch_settings.size, config->batch_settings.time);
4517}
static pthread_t cdr_thread
Definition: cdr.c:397
static ast_cond_t cdr_pending_cond
Definition: cdr.c:404
static void * do_cdr(void *data)
Definition: cdr.c:3982
#define LOG_NOTICE
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#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 4470 of file cdr.c.

4471{
4474
4476 cdr_topic = NULL;
4477
4478 STASIS_MESSAGE_TYPE_CLEANUP(cdr_sync_message_type);
4479
4485 sched = NULL;
4486 ast_free(batch);
4487 batch = NULL;
4488
4489 aco_info_destroy(&cfg_info);
4490 ao2_global_obj_release(module_configs);
4491
4492 ao2_container_unregister("cdrs_master");
4495
4496 ao2_container_unregister("cdrs_all");
4499}
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:4342
static struct ast_cli_entry cli_commands[]
Definition: cdr.c:4331
static void finalize_batch_mode(void)
Definition: cdr.c:4359
static struct stasis_topic * cdr_topic
The parent topic for all topics we want to aggregate for CDRs.
Definition: cdr.c:425
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 3084 of file cdr.c.

3085{
3086 struct ast_var_t *variables;
3087
3088 if (ast_strlen_zero(name)) {
3089 return NULL;
3090 }
3091
3092 AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
3093 if (!strcasecmp(name, ast_var_name(variables))) {
3094 return ast_var_value(variables);
3095 }
3096 }
3097
3098 return NULL;
3099}

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

2969{
2970 struct cdr_beitem *i;
2971 struct cdr_beitem *cur;
2972
2973 if (!name) {
2974 return -1;
2975 }
2976
2977 if (!be) {
2978 ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
2979
2980 return -1;
2981 }
2982
2983 i = ast_calloc(1, sizeof(*i));
2984 if (!i) {
2985 return -1;
2986 }
2987
2988 i->be = be;
2989 ast_copy_string(i->name, name, sizeof(i->name));
2990 ast_copy_string(i->desc, desc, sizeof(i->desc));
2991
2992 AST_RWLIST_WRLOCK(generic_list);
2993 AST_RWLIST_TRAVERSE(generic_list, cur, list) {
2994 if (!strcasecmp(name, cur->name)) {
2995 ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
2996 AST_RWLIST_UNLOCK(generic_list);
2997 ast_free(i);
2998
2999 return -1;
3000 }
3001 }
3002
3003 AST_RWLIST_INSERT_HEAD(generic_list, i, list);
3004 AST_RWLIST_UNLOCK(generic_list);
3005
3006 return 0;
3007}
#define LOG_WARNING
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
ast_cdrbe be
Definition: cdr.c:366
char desc[80]
Definition: cdr.c:365

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

3102{
3103 if (fmt == NULL) { /* raw mode */
3104 snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
3105 } else {
3106 buf[0] = '\0';/* Ensure the buffer is initialized. */
3107 if (when.tv_sec) {
3108 struct ast_tm tm;
3109
3110 ast_localtime(&when, &tm, NULL);
3111 ast_strftime(buf, bufsize, fmt, &tm);
3112 }
3113 }
3114}
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 898 of file cdr.c.

899{
900 struct cdr_object *left = obj;
901 struct cdr_object *right = arg;
902 const char *right_key = arg;
903 int cmp;
904
905 switch (flags & OBJ_SEARCH_MASK) {
907 right_key = right->uniqueid;
908 /* Fall through */
909 case OBJ_SEARCH_KEY:
910 cmp = strcmp(left->uniqueid, right_key);
911 break;
913 /*
914 * We could also use a partial key struct containing a length
915 * so strlen() does not get called for every comparison instead.
916 */
917 cmp = strncmp(left->uniqueid, right_key, strlen(right_key));
918 break;
919 default:
920 /* Sort can only work on something with a full or partial key. */
921 ast_assert(0);
922 cmp = 0;
923 break;
924 }
925 return cmp ? 0 : CMP_MATCH;
926}
const ast_string_field uniqueid
Definition: cdr.c:777

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

875{
876 const struct cdr_object *cdr;
877 const char *key;
878
879 switch (flags & OBJ_SEARCH_MASK) {
880 case OBJ_SEARCH_KEY:
881 key = obj;
882 break;
884 cdr = obj;
885 key = cdr->uniqueid;
886 break;
887 default:
888 ast_assert(0);
889 return 0;
890 }
891 return ast_str_case_hash(key);
892}

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

4529{
4530 struct cdr_object *cdr = v_obj;
4531 struct cdr_object *it_cdr;
4532
4533 if (!cdr) {
4534 return;
4535 }
4536 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4537 prnt(where, "Party A: %s; Party B: %s; Bridge %s\n",
4538 it_cdr->party_a.snapshot->base->name,
4539 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<unknown>",
4540 it_cdr->bridge);
4541 }
4542}

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

1081{
1082 struct cdr_object *cdr;
1083
1084 ast_assert(chan != NULL);
1085
1086 cdr = ao2_alloc(sizeof(*cdr), cdr_object_dtor);
1087 if (!cdr) {
1088 return NULL;
1089 }
1090 cdr->last = cdr;
1091 if (ast_string_field_init(cdr, 64)) {
1092 ao2_cleanup(cdr);
1093 return NULL;
1094 }
1096 ast_string_field_set(cdr, name, chan->base->name);
1101 cdr->lastevent = *event_time;
1102
1103 cdr->party_a.snapshot = chan;
1104 ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
1105
1106 CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->base->name);
1107
1109
1110 return cdr;
1111}
#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:615
static int global_cdr_sequence
The global sequence counter used for CDRs.
Definition: cdr.c:391
static void cdr_object_dtor(void *obj)
cdr_object Destructor
Definition: cdr.c:1039
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:757
#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:764
const ast_string_field tenantid
Definition: cdr.c:777
enum ast_cdr_disposition disposition
Definition: cdr.c:759

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

1538{
1539 if (cdr->party_a.snapshot->state == AST_STATE_UP && ast_tvzero(cdr->answer)) {
1540 cdr->answer = cdr->lastevent;
1541 /* tv_usec is suseconds_t, which could be int or long */
1542 CDR_DEBUG("%p - Set answered time to %ld.%06ld\n", cdr,
1543 (long)cdr->answer.tv_sec,
1544 (long)cdr->answer.tv_usec);
1545 }
1546}

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

1119{
1120 struct cdr_object *new_cdr;
1121 struct cdr_object *it_cdr;
1122 struct cdr_object *cdr_last;
1123
1124 cdr_last = cdr->last;
1125 new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot, event_time);
1126 if (!new_cdr) {
1127 return NULL;
1128 }
1129 new_cdr->disposition = AST_CDR_NULL;
1130
1131 /* Copy over the linkedid, as it may have changed */
1132 ast_string_field_set(new_cdr, linkedid, cdr_last->linkedid);
1133 ast_string_field_set(new_cdr, appl, cdr_last->appl);
1134 ast_string_field_set(new_cdr, data, cdr_last->data);
1135 ast_string_field_set(new_cdr, context, cdr_last->context);
1136 ast_string_field_set(new_cdr, exten, cdr_last->exten);
1137
1138 /*
1139 * If the current CDR says to disable all future ones,
1140 * keep the disable chain going
1141 */
1142 if (ast_test_flag(&cdr_last->flags, AST_CDR_FLAG_DISABLE_ALL)) {
1144 }
1145
1146 /* Copy over other Party A information */
1147 cdr_object_snapshot_copy(&new_cdr->party_a, &cdr_last->party_a);
1148
1149 /* Append the CDR to the end of the list */
1150 for (it_cdr = cdr; it_cdr->next; it_cdr = it_cdr->next) {
1151 it_cdr->last = new_cdr;
1152 }
1153 it_cdr->last = new_cdr;
1154 it_cdr->next = new_cdr;
1155
1156 return new_cdr;
1157}
static struct cdr_object * cdr_object_alloc(struct ast_channel_snapshot *chan, const struct timeval *event_time)
cdr_object constructor
Definition: cdr.c:1080
@ 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 1328 of file cdr.c.

1329{
1330 struct ast_cdr *pub_cdr = NULL, *cdr_prev = NULL;
1331 struct cdr_object *it_cdr;
1332 struct ast_var_t *it_var, *it_copy_var;
1333 struct ast_channel_snapshot *party_a;
1334 struct ast_channel_snapshot *party_b;
1335
1336 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
1337 struct ast_cdr *cdr_copy;
1338
1339 /* Don't create records for CDRs where the party A was a dialed channel */
1340 if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
1341 ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
1342 it_cdr->party_a.snapshot->base->name);
1343 continue;
1344 }
1345
1346 cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
1347 if (!cdr_copy) {
1348 ast_free(pub_cdr);
1349 return NULL;
1350 }
1351
1352 party_a = it_cdr->party_a.snapshot;
1353 party_b = it_cdr->party_b.snapshot;
1354
1355 /* Party A */
1356 ast_assert(party_a != NULL);
1357 ast_copy_string(cdr_copy->accountcode, party_a->base->accountcode, sizeof(cdr_copy->accountcode));
1358 cdr_copy->amaflags = party_a->amaflags;
1359 ast_copy_string(cdr_copy->channel, party_a->base->name, sizeof(cdr_copy->channel));
1360 ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller->name, party_a->caller->number, "");
1361 ast_copy_string(cdr_copy->src, party_a->caller->number, sizeof(cdr_copy->src));
1362 ast_copy_string(cdr_copy->uniqueid, party_a->base->uniqueid, sizeof(cdr_copy->uniqueid));
1363 ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
1364 ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
1365 ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
1366 ast_copy_string(cdr_copy->dcontext, it_cdr->context, sizeof(cdr_copy->dcontext));
1367 ast_copy_string(cdr_copy->tenantid, it_cdr->tenantid, sizeof(cdr_copy->tenantid));
1368
1369 /* Party B */
1370 if (party_b) {
1371 ast_copy_string(cdr_copy->dstchannel, party_b->base->name, sizeof(cdr_copy->dstchannel));
1372 ast_copy_string(cdr_copy->peeraccount, party_b->base->accountcode, sizeof(cdr_copy->peeraccount));
1373 if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
1374 snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
1375 }
1376 ast_copy_string(cdr_copy->peertenantid, party_b->base->tenantid, sizeof(cdr_copy->peertenantid));
1377 }
1378 if (ast_strlen_zero(cdr_copy->userfield) && !ast_strlen_zero(it_cdr->party_a.userfield)) {
1379 ast_copy_string(cdr_copy->userfield, it_cdr->party_a.userfield, sizeof(cdr_copy->userfield));
1380 }
1381
1382 /* Timestamps/durations */
1383 cdr_copy->start = it_cdr->start;
1384 cdr_copy->answer = it_cdr->answer;
1385 cdr_copy->end = it_cdr->end;
1386 cdr_copy->billsec = cdr_object_get_billsec(it_cdr);
1387 cdr_copy->duration = cdr_object_get_duration(it_cdr);
1388
1389 /* Flags and IDs */
1390 ast_copy_flags(cdr_copy, &it_cdr->flags, AST_FLAGS_ALL);
1391 ast_copy_string(cdr_copy->linkedid, it_cdr->linkedid, sizeof(cdr_copy->linkedid));
1392 cdr_copy->disposition = it_cdr->disposition;
1393 cdr_copy->sequence = it_cdr->sequence;
1394
1395 /* Variables */
1396 copy_variables(&cdr_copy->varshead, &it_cdr->party_a.variables);
1397 AST_LIST_TRAVERSE(&it_cdr->party_b.variables, it_var, entries) {
1398 int found = 0;
1399 struct ast_var_t *newvariable;
1400 AST_LIST_TRAVERSE(&cdr_copy->varshead, it_copy_var, entries) {
1401 if (!strcasecmp(ast_var_name(it_var), ast_var_name(it_copy_var))) {
1402 found = 1;
1403 break;
1404 }
1405 }
1406 if (!found && (newvariable = ast_var_assign(ast_var_name(it_var), ast_var_value(it_var)))) {
1407 AST_LIST_INSERT_TAIL(&cdr_copy->varshead, newvariable, entries);
1408 }
1409 }
1410
1411 if (!pub_cdr) {
1412 pub_cdr = cdr_copy;
1413 cdr_prev = pub_cdr;
1414 } else {
1415 cdr_prev->next = cdr_copy;
1416 cdr_prev = cdr_copy;
1417 }
1418 }
1419
1420 return pub_cdr;
1421}
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:1268
static long cdr_object_get_billsec(struct cdr_object *cdr)
Compute the billsec for a cdr_object.
Definition: cdr.c:1276
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:1220
#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 1429 of file cdr.c.

1430{
1431 struct ast_cdr *pub_cdr;
1432
1433 CDR_DEBUG("%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
1434 cdr->party_a.snapshot->base->name,
1435 cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<none>");
1436 pub_cdr = cdr_object_create_public_records(cdr);
1437 cdr_detach(pub_cdr);
1438}
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:1328
static void cdr_detach(struct ast_cdr *cdr)
Definition: cdr.c:3920

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

4343{
4344 struct cdr_object *cdr = obj;
4345 struct cdr_object *it_cdr;
4346
4347 ao2_lock(cdr);
4348 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4350 }
4352 ao2_unlock(cdr);
4353
4354 cdr_all_unlink(cdr);
4355
4356 return CMP_MATCH;
4357}
static void cdr_all_unlink(struct cdr_object *cdr)
Definition: cdr.c:1012
static void cdr_object_dispatch(struct cdr_object *cdr)
Dispatch a CDR.
Definition: cdr.c:1429

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

1040{
1041 struct cdr_object *cdr = obj;
1042 struct ast_var_t *it_var;
1043
1046 while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_a.variables, entries))) {
1047 ast_var_delete(it_var);
1048 }
1049 while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_b.variables, entries))) {
1050 ast_var_delete(it_var);
1051 }
1053
1054 /* CDR destruction used to work by calling ao2_cleanup(next) and
1055 * allowing the chain to destroy itself neatly. Unfortunately, for
1056 * really long chains, this can result in a stack overflow. So now
1057 * when the root CDR is destroyed, it is responsible for unreffing
1058 * all CDRs in the chain
1059 */
1060 if (cdr->is_root) {
1061 struct cdr_object *curr = cdr->next;
1062 struct cdr_object *next;
1063
1064 while (curr) {
1065 next = curr->next;
1066 ao2_cleanup(curr);
1067 curr = next;
1068 }
1069 }
1070}
#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 1483 of file cdr.c.

1484{
1485 if (!ast_tvzero(cdr->end)) {
1486 return;
1487 }
1488 cdr->end = cdr->lastevent;
1489
1490 if (cdr->disposition == AST_CDR_NULL) {
1491 if (!ast_tvzero(cdr->answer)) {
1493 } else if (cdr->party_a.snapshot->hangup->cause) {
1495 } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangup->cause) {
1497 } else {
1499 }
1500 }
1501
1502 /* tv_usec is suseconds_t, which could be int or long */
1503 ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dur %.3f bill %.3f dispo %s\n",
1504 cdr->party_a.snapshot->base->name,
1505 (long)cdr->start.tv_sec,
1506 (long)cdr->start.tv_usec,
1507 (long)cdr->answer.tv_sec,
1508 (long)cdr->answer.tv_usec,
1509 (long)cdr->end.tv_sec,
1510 (long)cdr->end.tv_usec,
1511 (double)ast_tvdiff_ms(cdr->end, cdr->start) / 1000.0,
1512 (double)ast_tvdiff_ms(cdr->end, cdr->answer) / 1000.0,
1514}
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:1445
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 2252 of file cdr.c.

2253{
2254 struct cdr_object *cdr = obj;
2255
2256 if (!strcasecmp(cdr->party_b_name, arg)) {
2257#ifdef AST_DEVMODE
2258 struct ast_channel_snapshot *party_b = data;
2259
2260 /*
2261 * For sanity's sake we also assert the party_b snapshot
2262 * is consistent with the key.
2263 */
2265 && !strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name));
2266#endif
2267
2268 /* Don't transition to the finalized state - let the Party A do
2269 * that when its ready
2270 */
2272 }
2273 return 0;
2274}

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

3315{
3316 struct ast_channel_snapshot *party_a = cdr_obj->party_a.snapshot;
3317 struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
3318
3319 if (!strcasecmp(name, "clid")) {
3320 ast_callerid_merge(value, length, party_a->caller->name, party_a->caller->number, "");
3321 } else if (!strcasecmp(name, "src")) {
3322 ast_copy_string(value, party_a->caller->number, length);
3323 } else if (!strcasecmp(name, "dst")) {
3324 ast_copy_string(value, party_a->dialplan->exten, length);
3325 } else if (!strcasecmp(name, "dcontext")) {
3326 ast_copy_string(value, party_a->dialplan->context, length);
3327 } else if (!strcasecmp(name, "channel")) {
3328 ast_copy_string(value, party_a->base->name, length);
3329 } else if (!strcasecmp(name, "dstchannel")) {
3330 if (party_b) {
3331 ast_copy_string(value, party_b->base->name, length);
3332 } else {
3333 ast_copy_string(value, "", length);
3334 }
3335 } else if (!strcasecmp(name, "lastapp")) {
3336 ast_copy_string(value, party_a->dialplan->appl, length);
3337 } else if (!strcasecmp(name, "lastdata")) {
3338 ast_copy_string(value, party_a->dialplan->data, length);
3339 } else if (!strcasecmp(name, "start")) {
3340 cdr_get_tv(cdr_obj->start, NULL, value, length);
3341 } else if (!strcasecmp(name, "answer")) {
3342 cdr_get_tv(cdr_obj->answer, NULL, value, length);
3343 } else if (!strcasecmp(name, "end")) {
3344 cdr_get_tv(cdr_obj->end, NULL, value, length);
3345 } else if (!strcasecmp(name, "duration")) {
3346 snprintf(value, length, "%ld", cdr_object_get_duration(cdr_obj));
3347 } else if (!strcasecmp(name, "billsec")) {
3348 snprintf(value, length, "%ld", cdr_object_get_billsec(cdr_obj));
3349 } else if (!strcasecmp(name, "disposition")) {
3350 snprintf(value, length, "%u", cdr_obj->disposition);
3351 } else if (!strcasecmp(name, "amaflags")) {
3352 snprintf(value, length, "%d", party_a->amaflags);
3353 } else if (!strcasecmp(name, "accountcode")) {
3354 ast_copy_string(value, party_a->base->accountcode, length);
3355 } else if (!strcasecmp(name, "peeraccount")) {
3356 if (party_b) {
3357 ast_copy_string(value, party_b->base->accountcode, length);
3358 } else {
3359 ast_copy_string(value, "", length);
3360 }
3361 } else if (!strcasecmp(name, "uniqueid")) {
3362 ast_copy_string(value, party_a->base->uniqueid, length);
3363 } else if (!strcasecmp(name, "linkedid")) {
3364 ast_copy_string(value, cdr_obj->linkedid, length);
3365 } else if (!strcasecmp(name, "tenantid")) {
3366 ast_copy_string(value, party_a->base->tenantid, length);
3367 } else if (!strcasecmp(name, "peertenantid")) {
3368 if (party_b) {
3369 ast_copy_string(value, party_b->base->tenantid, length);
3370 } else {
3371 ast_copy_string(value, "", length);
3372 }
3373 } else if (!strcasecmp(name, "userfield")) {
3374 ast_copy_string(value, cdr_obj->party_a.userfield, length);
3375 } else if (!strcasecmp(name, "sequence")) {
3376 snprintf(value, length, "%u", cdr_obj->sequence);
3377 } else {
3378 return 1;
3379 }
3380
3381 return 0;
3382}

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

3298{
3299 struct ast_var_t *variable;
3300
3301 AST_LIST_TRAVERSE(&cdr->party_a.variables, variable, entries) {
3302 if (!strcasecmp(name, ast_var_name(variable))) {
3303 ast_copy_string(value, ast_var_value(variable), length);
3304 return;
3305 }
3306 }
3307
3308 *value = '\0';
3309}

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

1277{
1278 long int ms;
1279
1280 if (ast_tvzero(cdr->answer)) {
1281 return 0;
1282 }
1283
1284 ms = ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->answer);
1285 if (ms % 1000 >= 500
1287 ms = (ms / 1000) + 1;
1288 } else {
1289 ms = ms / 1000;
1290 }
1291
1292 return ms;
1293}
@ 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 3391 of file cdr.c.

3392{
3393 char *param;
3394
3395 if (ast_strlen_zero(name)) {
3396 return NULL;
3397 }
3398
3399 param = ast_strdupa(name);
3401}
static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
Definition: cdr.c:3212

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

3213{
3214 struct cdr_object *cdr = obj;
3215 const char *name = arg;
3216
3217 if (!strcasecmp(cdr->party_a.snapshot->base->name, name)) {
3218 return CMP_MATCH;
3219 }
3220 return 0;
3221}

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

1269{
1270 return (long)(ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->start) / 1000);
1271}

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

2430{
2431 struct cdr_object *cdr = obj;
2432 struct bridge_leave_data *leave_data = data;
2433
2434 if (cdr->fn_table == &bridge_state_fn_table
2435 && !strcmp(cdr->bridge, leave_data->bridge->uniqueid)
2436 && !strcasecmp(cdr->party_b_name, arg)) {
2437 /*
2438 * For sanity's sake we also assert the party_b snapshot
2439 * is consistent with the key.
2440 */
2442 && !strcasecmp(cdr->party_b.snapshot->base->name, leave_data->channel->base->name));
2443
2444 /* It is our Party B, in our bridge. Set the last event and let the handler
2445 * transition our CDR appropriately when we leave the bridge.
2446 */
2447 cdr->lastevent = *leave_data->lastevent;
2449 }
2450 return 0;
2451}
const struct timeval * lastevent
Definition: cdr.c:2425
struct ast_bridge_snapshot * bridge
Definition: cdr.c:2423
struct ast_channel_snapshot * channel
Definition: cdr.c:2424

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

1234{
1235 /* Check whether or not the party is dialed. A dialed party is never the
1236 * Party A with a party that was not dialed.
1237 */
1238 if (!snapshot_is_dialed(left->snapshot) && snapshot_is_dialed(right->snapshot)) {
1239 return left;
1240 } else if (snapshot_is_dialed(left->snapshot) && !snapshot_is_dialed(right->snapshot)) {
1241 return right;
1242 }
1243
1244 /* Try the Party A flag */
1246 return left;
1248 return right;
1249 }
1250
1251 /* Neither party is dialed and neither has the Party A flag - defer to
1252 * creation time */
1253 if (left->snapshot->base->creationtime.tv_sec < right->snapshot->base->creationtime.tv_sec) {
1254 return left;
1255 } else if (left->snapshot->base->creationtime.tv_sec > right->snapshot->base->creationtime.tv_sec) {
1256 return right;
1257 } else if (left->snapshot->base->creationtime.tv_usec > right->snapshot->base->creationtime.tv_usec) {
1258 return right;
1259 } else {
1260 /* Okay, fine, take the left one */
1261 return left;
1262 }
1263}
@ 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 3196 of file cdr.c.

3197{
3198 struct cdr_object *cdr = obj;
3199 const char *name = arg;
3200
3201 if (!strcasecmp(cdr->party_a.snapshot->base->name, name) ||
3202 (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->base->name, name))) {
3203 return CMP_MATCH;
3204 }
3205 return 0;
3206}

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

1446{
1447 /* Change the disposition based on the hang up cause */
1448 switch (hangupcause) {
1449 case AST_CAUSE_BUSY:
1451 break;
1455 } else {
1457 }
1458 break;
1462 break;
1466 break;
1467 default:
1468 break;
1469 }
1470}
#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 834 of file cdr.c.

835{
836 ao2_t_replace(dst->snapshot, src->snapshot, "CDR snapshot copy");
837 strcpy(dst->userfield, src->userfield);
838 dst->flags = src->flags;
839 copy_variables(&dst->variables, &src->variables);
840}
#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 1574 of file cdr.c.

1576{
1577 cdr_object_update_cid(old_snapshot, new_snapshot);
1578 ao2_t_replace(old_snapshot->snapshot, new_snapshot, "Swap CDR shapshot");
1579}
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:1549

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

849{
850 CDR_DEBUG("%p - Transitioning CDR for %s from state %s to %s\n",
851 cdr, cdr->party_a.snapshot->base->name,
852 cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
853 cdr->fn_table = fn_table;
854
855 if (cdr->fn_table->init_function && do_init) {
856 cdr->fn_table->init_function(cdr);
857 }
858}
const char * name
Name of the subclass.
Definition: cdr.c:460
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:469

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

1550{
1551 if (!old_snapshot->snapshot) {
1552 set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1553 set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1554 set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1555 return;
1556 }
1557 if (strcmp(old_snapshot->snapshot->caller->dnid, new_snapshot->caller->dnid)) {
1558 set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1559 }
1560 if (strcmp(old_snapshot->snapshot->caller->subaddr, new_snapshot->caller->subaddr)) {
1561 set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1562 }
1563 if (strcmp(old_snapshot->snapshot->caller->dialed_subaddr, new_snapshot->caller->dialed_subaddr)) {
1564 set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1565 }
1566}
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 2276 of file cdr.c.

2277{
2278 struct cdr_object *cdr = obj;
2279
2280 if (cdr->fn_table->process_party_b
2281 && !strcasecmp(cdr->party_b_name, arg)) {
2282 struct ast_channel_snapshot *party_b = data;
2283
2284 /*
2285 * For sanity's sake we also check the party_b snapshot
2286 * for consistency with the key. The callback needs and
2287 * asserts the snapshot to be this way.
2288 */
2289 if (!cdr->party_b.snapshot
2290 || strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name)) {
2292 "CDR for Party A %s(%s) has inconsistent Party B %s name. Message can be ignored but this shouldn't happen.\n",
2293 cdr->linkedid,
2294 cdr->party_a.snapshot->base->name,
2295 cdr->party_b_name);
2296 return 0;
2297 }
2298
2299 cdr->fn_table->process_party_b(cdr, party_b);
2300 }
2301 return 0;
2302}
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:488

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

3535{
3536 struct cdr_object *cdr = obj;
3537
3538 if ((cdr->fn_table != &finalized_state_fn_table || !cdr->next)
3539 && !strcasecmp(cdr->party_b_name, arg)) {
3540 struct party_b_userfield_update *info = data;
3541
3542 /*
3543 * For sanity's sake we also assert the party_b snapshot
3544 * is consistent with the key.
3545 */
3547 && !strcasecmp(cdr->party_b.snapshot->base->name, info->channel_name));
3548
3549 ast_copy_string(cdr->party_b.userfield, info->userfield,
3550 sizeof(cdr->party_b.userfield));
3551 }
3552
3553 return 0;
3554}
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 3845 of file cdr.c.

3846{
3847 struct module_config *mod_cfg;
3848 struct cdr_batch_item *oldbatchitems = NULL;
3849 pthread_t batch_post_thread = AST_PTHREADT_NULL;
3850
3851 /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
3852 if (!batch || !batch->head) {
3853 return;
3854 }
3855
3856 /* move the old CDRs aside, and prepare a new CDR batch */
3858 oldbatchitems = batch->head;
3859 reset_batch();
3861
3862 mod_cfg = ao2_global_obj_ref(module_configs);
3863
3864 /* if configured, spawn a new thread to post these CDRs,
3865 also try to save as much as possible if we are shutting down safely */
3866 if (!mod_cfg
3868 || do_shutdown) {
3869 ast_debug(1, "CDR single-threaded batch processing begins now\n");
3870 do_batch_backend_process(oldbatchitems);
3871 } else {
3872 if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
3873 ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
3874 do_batch_backend_process(oldbatchitems);
3875 } else {
3876 ast_debug(1, "CDR multi-threaded batch processing begins now\n");
3877 }
3878 }
3879
3880 ao2_cleanup(mod_cfg);
3881}
static void reset_batch(void)
Definition: cdr.c:3809
static void * do_batch_backend_process(void *data)
Definition: cdr.c:3828
@ 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 4569 of file cdr.c.

4570{
4571 struct module_config *mod_cfg;
4572
4573 mod_cfg = ao2_global_obj_ref(module_configs);
4574 if (mod_cfg
4575 && ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4576 if (create_subscriptions()) {
4578 ast_log(AST_LOG_ERROR, "Failed to create Stasis subscriptions\n");
4579 ao2_cleanup(mod_cfg);
4580 return -1;
4581 }
4582 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4584 } else {
4585 ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
4586 }
4587 } else {
4589 ast_log(LOG_NOTICE, "CDR logging disabled.\n");
4590 }
4591 ao2_cleanup(mod_cfg);
4592
4593 return mod_cfg ? 0 : -1;
4594}
static int create_subscriptions(void)
Create the Stasis subcriptions for CDRs.
Definition: cdr.c:4396
static void cdr_enable_batch_mode(struct ast_cdr_config *config)
Definition: cdr.c:4501
static void destroy_subscriptions(void)
Destroy the active Stasis subscriptions.
Definition: cdr.c:4386
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 2305 of file cdr.c.

2307{
2308 /* If we're dead, we don't need a new CDR */
2309 if (!new_snapshot
2312 return 0;
2313 }
2314
2315 /* Auto-fall through will increment the priority but have no application */
2316 if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
2317 return 0;
2318 }
2319
2320 if (old_snapshot && !snapshot_cep_changed(old_snapshot, new_snapshot)) {
2321 return 0;
2322 }
2323
2324 return 1;
2325}
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:1189

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

4050{
4051 int wordlen = strlen(a->word);
4052 struct ao2_iterator it_cdrs;
4053 struct cdr_object *cdr;
4054
4056 while ((cdr = ao2_iterator_next(&it_cdrs))) {
4057 if (!strncasecmp(a->word, cdr->party_a.snapshot->base->name, wordlen)) {
4059 ao2_ref(cdr, -1);
4060 break;
4061 }
4062 }
4063 ao2_ref(cdr, -1);
4064 }
4065 ao2_iterator_destroy(&it_cdrs);
4066
4067 return NULL;
4068}
#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 4134 of file cdr.c.

4135{
4136 struct cdr_object *it_cdr;
4137 char clid[64];
4138 char start_time_buffer[64];
4139 char answer_time_buffer[64];
4140 char end_time_buffer[64];
4141 const char *channel_name = a->argv[3];
4142 struct cdr_object *cdr;
4143
4144#define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4145#define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4146
4147 cdr = cdr_object_get_by_name(channel_name);
4148 if (!cdr) {
4149 ast_cli(a->fd, "Unknown channel: %s\n", channel_name);
4150 return;
4151 }
4152
4153 ast_cli(a->fd, "\n");
4154 ast_cli(a->fd, "Call Detail Record (CDR) Information for %s\n", channel_name);
4155 ast_cli(a->fd, "--------------------------------------------------\n");
4156 ast_cli(a->fd, TITLE_STRING, "AccountCode", "CallerID", "Dst. Channel", "LastApp", "Data", "Start", "Answer", "End", "Billsec", "Duration");
4157
4158 ao2_lock(cdr);
4159 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4160 struct timeval end;
4161
4162 if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4163 continue;
4164 }
4165 ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller->name, it_cdr->party_a.snapshot->caller->number, "");
4166 if (ast_tvzero(it_cdr->end)) {
4167 end = ast_tvnow();
4168 } else {
4169 end = it_cdr->end;
4170 }
4171 cdr_get_tv(it_cdr->start, "%T", start_time_buffer, sizeof(start_time_buffer));
4172 cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4173 cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
4174 ast_cli(a->fd, FORMAT_STRING,
4175 it_cdr->party_a.snapshot->base->accountcode,
4176 clid,
4177 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4178 it_cdr->appl,
4179 it_cdr->data,
4180 start_time_buffer,
4181 answer_time_buffer,
4182 end_time_buffer,
4183 (long)ast_tvdiff_ms(end, it_cdr->answer) / 1000,
4184 (long)ast_tvdiff_ms(end, it_cdr->start) / 1000);
4185 }
4186 ao2_unlock(cdr);
4187
4188 ao2_cleanup(cdr);
4189
4190#undef FORMAT_STRING
4191#undef TITLE_STRING
4192}
#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 4070 of file cdr.c.

4071{
4072 struct ao2_iterator it_cdrs;
4073 struct cdr_object *cdr;
4074 char start_time_buffer[64];
4075 char answer_time_buffer[64];
4076 char end_time_buffer[64];
4077
4078#define TITLE_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4079#define FORMAT_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4080
4081 ast_cli(a->fd, "\n");
4082 ast_cli(a->fd, "Channels with Call Detail Record (CDR) Information\n");
4083 ast_cli(a->fd, "--------------------------------------------------\n");
4084 ast_cli(a->fd, TITLE_STRING, "Channel", "Dst. Channel", "LastApp", "Start", "Answer", "End", "Billsec", "Duration");
4085
4087 for (; (cdr = ao2_iterator_next(&it_cdrs)); ao2_cleanup(cdr)) {
4088 struct cdr_object *it_cdr;
4089 struct timeval start_time = { 0, };
4090 struct timeval answer_time = { 0, };
4091 struct timeval end_time = { 0, };
4092
4093 SCOPED_AO2LOCK(lock, cdr);
4094
4095 /* Calculate the start, end, answer, billsec, and duration over the
4096 * life of all of the CDR entries
4097 */
4098 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4099 if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4100 continue;
4101 }
4102 if (ast_tvzero(start_time)) {
4103 start_time = it_cdr->start;
4104 }
4105 if (!ast_tvzero(it_cdr->answer) && ast_tvzero(answer_time)) {
4106 answer_time = it_cdr->answer;
4107 }
4108 }
4109
4110 /* If there was no start time, then all CDRs were for a dialed channel; skip */
4111 if (ast_tvzero(start_time)) {
4112 continue;
4113 }
4114 it_cdr = cdr->last;
4115
4116 end_time = ast_tvzero(it_cdr->end) ? ast_tvnow() : it_cdr->end;
4117 cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
4118 cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4119 cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
4121 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4122 it_cdr->appl,
4123 start_time_buffer,
4124 answer_time_buffer,
4125 end_time_buffer,
4126 ast_tvzero(answer_time) ? 0 : (long)ast_tvdiff_ms(end_time, answer_time) / 1000,
4127 (long)ast_tvdiff_ms(end_time, start_time) / 1000);
4128 }
4129 ao2_iterator_destroy(&it_cdrs);
4130#undef FORMAT_STRING
4131#undef TITLE_STRING
4132}

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

790{
791 struct ast_var_t *variables;
792 struct ast_var_t *newvariable;
793 const char *var;
794 const char *val;
795 int x = 0;
796
797 AST_LIST_TRAVERSE(from_list, variables, entries) {
798 var = ast_var_name(variables);
799 if (ast_strlen_zero(var)) {
800 continue;
801 }
802 val = ast_var_value(variables);
803 if (ast_strlen_zero(val)) {
804 continue;
805 }
806 newvariable = ast_var_assign(var, val);
807 if (newvariable) {
808 AST_LIST_INSERT_HEAD(to_list, newvariable, entries);
809 ++x;
810 }
811 }
812
813 return x;
814}
#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 subcriptions for CDRs.

Definition at line 4396 of file cdr.c.

4397{
4398 if (!cdr_topic) {
4399 return -1;
4400 }
4401
4403 return 0;
4404 }
4405
4407 if (!channel_subscription) {
4408 return -1;
4409 }
4411 if (!bridge_subscription) {
4412 return -1;
4413 }
4415 if (!parking_subscription) {
4416 return -1;
4417 }
4418
4419 return 0;
4420}
static struct stasis_forward * bridge_subscription
Our subscription for bridges.
Definition: cdr.c:416
static struct stasis_forward * channel_subscription
Our subscription for channels.
Definition: cdr.c:419
static struct stasis_forward * parking_subscription
Our subscription for parking.
Definition: cdr.c:422
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:1579
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 4386 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 1923 of file cdr.c.

1924{
1925 int success = 0;
1926
1927 ast_string_field_set(cdr, bridge, bridge->uniqueid);
1928
1929 /* Get parties in the bridge */
1930 if (ao2_container_count(bridge->channels) == 1) {
1931 /* No one in the bridge yet but us! */
1934 }
1935
1936 /* If we don't have a Party B (originated channel), skip it */
1937 if (cdr->party_b.snapshot) {
1938 struct ao2_iterator it_cdrs;
1939 char *channel_id;
1940
1941 for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
1942 !success && (channel_id = ao2_iterator_next(&it_cdrs));
1943 ao2_ref(channel_id, -1)) {
1944 struct cdr_object *cand_cdr_master;
1945 struct cdr_object *cand_cdr;
1946
1947 cand_cdr_master = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
1948 if (!cand_cdr_master) {
1949 continue;
1950 }
1951
1952 ao2_lock(cand_cdr_master);
1953 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
1954 /* Skip any records that are not in a bridge or in this bridge.
1955 * I'm not sure how that would happen, but it pays to be careful. */
1956 if (cand_cdr->fn_table != &bridge_state_fn_table
1957 || strcmp(cdr->bridge, cand_cdr->bridge)) {
1958 continue;
1959 }
1960
1961 /* Skip any records that aren't our Party B */
1962 if (strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
1963 continue;
1964 }
1965 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
1966 /* If they have a Party B, they joined up with someone else as their
1967 * Party A. Don't finalize them as they're active. Otherwise, we
1968 * have stolen them so they need to be finalized.
1969 */
1970 if (!cand_cdr->party_b.snapshot) {
1971 cdr_object_finalize(cand_cdr);
1972 }
1973 success = 1;
1974 break;
1975 }
1976 ao2_unlock(cand_cdr_master);
1977 ao2_cleanup(cand_cdr_master);
1978 }
1979 ao2_iterator_destroy(&it_cdrs);
1980 }
1981
1982 /* We always transition state, even if we didn't get a peer */
1984
1985 /* Success implies that we have a Party B */
1986 if (success) {
1988 }
1990}
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_container * channels
Definition: bridge.h:331

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

1860{
1861 /* Don't process a begin dial here. A party A already in the dial state will
1862 * who receives a dial begin for something else will be handled by the
1863 * message router callback and will add a new CDR for the party A */
1864 return 1;
1865}

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

1892{
1893 struct ast_channel_snapshot *party_a;
1894
1895 if (caller) {
1896 party_a = caller;
1897 } else {
1898 party_a = peer;
1899 }
1900 ast_assert(!strcasecmp(cdr->party_a.snapshot->base->name, party_a->base->name));
1901 cdr_object_swap_snapshot(&cdr->party_a, party_a);
1902
1903 if (cdr->party_b.snapshot) {
1904 if (strcasecmp(cdr->party_b.snapshot->base->name, peer->base->name)) {
1905 /* Not the status for this CDR - defer back to the message router */
1906 return 1;
1907 }
1909 }
1910
1911 /* Set the disposition based on the dial string. */
1912 cdr->disposition = dial_status_to_disposition(dial_status);
1913 if (cdr->disposition == AST_CDR_ANSWERED) {
1914 /* Switch to dial pending to wait and see what the caller does */
1916 } else {
1918 }
1919
1920 return 0;
1921}
static enum ast_cdr_disposition dial_status_to_disposition(const char *dial_status)
Definition: cdr.c:1871
struct cdr_object_fn_table dialed_pending_state_fn_table
The virtual table for the Dialed Pending state.
Definition: cdr.c:679

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

2133{
2134 return (strcmp(dialstatus, "RINGING") &&
2135 strcmp(dialstatus, "PROCEEDING") &&
2136 strcmp(dialstatus, "PROGRESS"));
2137}

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

1872{
1873 if (!strcmp(dial_status, "ANSWER")) {
1874 return AST_CDR_ANSWERED;
1875 } else if (!strcmp(dial_status, "BUSY")) {
1876 return AST_CDR_BUSY;
1877 } else if (!strcmp(dial_status, "CANCEL") || !strcmp(dial_status, "NOANSWER")) {
1878 return AST_CDR_NOANSWER;
1879 } else if (!strcmp(dial_status, "CONGESTION")) {
1881 return AST_CDR_FAILED;
1882 } else {
1883 return AST_CDR_CONGESTION;
1884 }
1885 } else if (!strcmp(dial_status, "FAILED")) {
1886 return AST_CDR_FAILED;
1887 }
1888 return AST_CDR_FAILED;
1889}

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

2020{
2022 return cdr->fn_table->process_bridge_enter(cdr, bridge, channel);
2023}
struct cdr_object_fn_table dial_state_fn_table
The virtual table for the Dial state.
Definition: cdr.c:646
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:545

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

2036{
2038
2039 /* Ask for a new CDR */
2040 return 1;
2041}

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

2026{
2027 if (cdr->party_b.snapshot) {
2028 /* We can't handle this as we have a Party B - ask for a new one */
2029 return 1;
2030 }
2032 return 0;
2033}
struct cdr_object_fn_table parked_state_fn_table
The virtual table for the Parked state.
Definition: cdr.c:720

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

1995{
1996 /* If we get a CEP change, we're executing dialplan. If we have a Party B
1997 * that means we need a new CDR; otherwise, switch us over to single.
1998 */
1999 if (snapshot_cep_changed(cdr->party_a.snapshot, snapshot)) {
2000 if (cdr->party_b.snapshot) {
2002 cdr->fn_table->process_party_a(cdr, snapshot);
2003 return 1;
2004 } else {
2005 /* The CDR does not need to be reinitialized when transitioning
2006 * to its single state as this would overwrite the start time,
2007 * causing potentially both the answer and the start time to be
2008 * the same which is incorrect.
2009 */
2011 cdr->fn_table->process_party_a(cdr, snapshot);
2012 return 0;
2013 }
2014 }
2015 base_process_party_a(cdr, snapshot);
2016 return 0;
2017}
static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition: cdr.c:1583

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

3829{
3830 struct cdr_batch_item *processeditem;
3831 struct cdr_batch_item *batchitem = data;
3832
3833 /* Push each CDR into storage mechanism(s) and free all the memory */
3834 while (batchitem) {
3835 post_cdr(batchitem->cdr);
3836 ast_cdr_free(batchitem->cdr);
3837 processeditem = batchitem;
3838 batchitem = batchitem->next;
3839 ast_free(processeditem);
3840 }
3841
3842 return NULL;
3843}

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

3983{
3984 struct timespec timeout;
3985 int schedms;
3986 int numevents = 0;
3987
3988 for (;;) {
3989 struct timeval now;
3990 schedms = ast_sched_wait(sched);
3991 /* this shouldn't happen, but provide a 1 second default just in case */
3992 if (schedms < 0)
3993 schedms = 1000;
3994 now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
3995 timeout.tv_sec = now.tv_sec;
3996 timeout.tv_nsec = now.tv_usec * 1000;
3997 /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
4000 numevents = ast_sched_runq(sched);
4002 ast_debug(2, "Processed %d CDR batches from the run queue\n", numevents);
4003 }
4004
4005 return NULL;
4006}
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:403
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:206
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 2454 of file cdr.c.

2455{
2456 /* Ignore holding bridge technology messages. We treat this simply as an application
2457 * that a channel enters into.
2458 */
2459 if (!strcmp(bridge->technology, "holding_bridge") && strcmp(bridge->subclass, "parking")) {
2460 return 1;
2461 }
2462 return 0;
2463}
const ast_string_field technology
Definition: bridge.h:328
const ast_string_field subclass
Definition: bridge.h:328

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

2108{
2109 return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
2110}
@ 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 2116 of file cdr.c.

2118{
2119 int ret = 0;
2120
2121 /* Drop cache updates from certain channel technologies */
2122 if (old_snapshot) {
2123 ret |= filter_channel_snapshot(old_snapshot);
2124 }
2125 if (new_snapshot) {
2126 ret |= filter_channel_snapshot(new_snapshot);
2127 }
2128
2129 return ret;
2130}
static int filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
Definition: cdr.c:2107

References filter_channel_snapshot().

Referenced by handle_channel_snapshot_update_message().

◆ finalize_batch_mode()

static void finalize_batch_mode ( void  )
static

Definition at line 4359 of file cdr.c.

4360{
4362 return;
4363 }
4364 /* wake up the thread so it will exit */
4365 pthread_cancel(cdr_thread);
4366 pthread_kill(cdr_thread, SIGURG);
4367 pthread_join(cdr_thread, NULL);
4371}
void ast_cdr_engine_term(void)
Definition: cdr.c:4682
#define ast_cond_destroy(cond)
Definition: lock.h:202

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

2088{
2090}

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

2093{
2096 return 0;
2097 }
2098
2099 /* Indicate that, if possible, we should get a new CDR */
2100 return 1;
2101}

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

821{
822 struct ast_var_t *vardata;
823
824 while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
825 ast_var_delete(vardata);
826 }
827}

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

2778{
2780 struct ast_bridge_snapshot *bridge = update->bridge;
2781 struct ast_channel_snapshot *channel = update->channel;
2782 struct cdr_object *cdr;
2783
2785 return;
2786 }
2787
2788 if (filter_channel_snapshot(channel)) {
2789 return;
2790 }
2791
2792 CDR_DEBUG("Bridge Enter message for channel %s: %u.%08u\n",
2793 channel->base->name,
2794 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2795 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2796
2798 if (!cdr) {
2799 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2800 ast_assert(0);
2801 return;
2802 }
2803
2804 if (!strcmp(bridge->subclass, "parking")) {
2806 } else {
2808 }
2809 ao2_cleanup(cdr);
2810}
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:2696
static int filter_bridge_messages(struct ast_bridge_snapshot *bridge)
Filter bridge messages based on bridge technology.
Definition: cdr.c:2454
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:2654
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:314

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

2473{
2475 struct ast_bridge_snapshot *bridge = update->bridge;
2476 struct ast_channel_snapshot *channel = update->channel;
2477 struct cdr_object *cdr;
2478 struct cdr_object *it_cdr;
2479 struct bridge_leave_data leave_data = {
2480 .bridge = bridge,
2481 .channel = channel,
2482 .lastevent = stasis_message_timestamp(message)
2483 };
2484 int left_bridge = 0;
2485
2487 return;
2488 }
2489
2491 return;
2492 }
2493
2494 CDR_DEBUG("Bridge Leave message for %s: %u.%08u\n",
2495 channel->base->name,
2496 (unsigned int)leave_data.lastevent->tv_sec,
2497 (unsigned int)leave_data.lastevent->tv_usec);
2498
2500 if (!cdr) {
2501 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2502 ast_assert(0);
2503 return;
2504 }
2505
2506 /* Party A */
2507 ao2_lock(cdr);
2508 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2509 it_cdr->lastevent = *leave_data.lastevent;
2510 if (!it_cdr->fn_table->process_bridge_leave) {
2511 continue;
2512 }
2513 CDR_DEBUG("%p - Processing Bridge Leave for %s\n",
2514 it_cdr, channel->base->name);
2515 if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
2516 ast_string_field_set(it_cdr, bridge, "");
2517 left_bridge = 1;
2518 }
2519 }
2520 ao2_unlock(cdr);
2521
2522 /* Party B */
2523 if (left_bridge
2524 && strcmp(bridge->subclass, "parking")) {
2526 cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->base->name,
2527 &leave_data);
2528 }
2529
2530 ao2_cleanup(cdr);
2531}
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:2429
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:575

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

2629{
2630 struct ao2_iterator it_channels;
2631 char *channel_id;
2632
2633 it_channels = ao2_iterator_init(bridge->channels, 0);
2634 while ((channel_id = ao2_iterator_next(&it_channels))) {
2635 struct cdr_object *cand_cdr;
2636
2637 cand_cdr = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
2638 if (cand_cdr) {
2639 bridge_candidate_process(cdr, cand_cdr);
2640 ao2_ref(cand_cdr, -1);
2641 }
2642
2643 ao2_ref(channel_id, -1);
2644 }
2645 ao2_iterator_destroy(&it_channels);
2646}
static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr)
Process a single bridge_candidate.
Definition: cdr.c:2570

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

2888{
2889 return;
2890}

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

2334{
2335 struct cdr_object *cdr;
2337 struct cdr_object *it_cdr;
2338
2339 if (filter_channel_snapshot_message(update->old_snapshot, update->new_snapshot)) {
2340 return;
2341 }
2342
2343 if (update->new_snapshot && !update->old_snapshot) {
2344 struct module_config *mod_cfg = NULL;
2345
2347 if (!cdr) {
2348 return;
2349 }
2350 mod_cfg = ao2_global_obj_ref(module_configs);
2351 cdr->is_root = 1;
2353
2354 /* If CDR should be disabled unless enabled on a per-channel basis, then disable
2355 CDR, right from the get go */
2356 if (mod_cfg) {
2358 ast_debug(3, "Disable CDR by default\n");
2360 }
2361 ao2_cleanup(mod_cfg);
2362 }
2363 } else {
2364 cdr = ao2_find(active_cdrs_master, update->new_snapshot->base->uniqueid, OBJ_SEARCH_KEY);
2365 }
2366
2367 /* Handle Party A */
2368 if (!cdr) {
2369 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->base->name);
2370 ast_assert(0);
2371 } else {
2372 int all_reject = 1;
2373
2374 ao2_lock(cdr);
2375 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2377 if (!it_cdr->fn_table->process_party_a) {
2378 continue;
2379 }
2380 all_reject &= it_cdr->fn_table->process_party_a(it_cdr, update->new_snapshot);
2381 }
2382 if (all_reject && check_new_cdr_needed(update->old_snapshot, update->new_snapshot)) {
2383 /* We're not hung up and we have a new snapshot - we need a new CDR */
2384 struct cdr_object *new_cdr;
2385
2387 if (new_cdr) {
2388 new_cdr->fn_table->process_party_a(new_cdr, update->new_snapshot);
2389 }
2390 }
2391 ao2_unlock(cdr);
2392 }
2393
2394 if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
2395 ao2_lock(cdr);
2396 CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->base->name);
2397 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2399 cdr_object_finalize(it_cdr);
2400 }
2402 ao2_unlock(cdr);
2403
2404 cdr_all_unlink(cdr);
2406 }
2407
2408 /* Handle Party B */
2409 if (update->new_snapshot) {
2411 cdr_object_update_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
2412 }
2413
2414 if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
2416 cdr_object_finalize_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
2417 }
2418
2419 ao2_cleanup(cdr);
2420}
#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:2276
static int cdr_object_finalize_party_b(void *obj, void *arg, void *data, int flags)
Definition: cdr.c:2252
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:2305
static int filter_channel_snapshot_message(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Definition: cdr.c:2116
@ 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 4008 of file cdr.c.

4009{
4010 struct module_config *mod_cfg;
4011
4012 switch (cmd) {
4013 case CLI_INIT:
4014 e->command = "cdr set debug [on|off]";
4015 e->usage = "Enable or disable extra debugging in the CDR Engine. Note\n"
4016 "that this will dump debug information to the VERBOSE setting\n"
4017 "and should only be used when debugging information from the\n"
4018 "CDR engine is needed.\n";
4019 return NULL;
4020 case CLI_GENERATE:
4021 return NULL;
4022 }
4023
4024 if (a->argc != 4) {
4025 return CLI_SHOWUSAGE;
4026 }
4027
4028 mod_cfg = ao2_global_obj_ref(module_configs);
4029 if (!mod_cfg) {
4030 ast_cli(a->fd, "Could not set CDR debugging mode\n");
4031 return CLI_SUCCESS;
4032 }
4033 if (!strcasecmp(a->argv[3], "on")
4034 && !ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
4036 ast_cli(a->fd, "CDR debugging enabled\n");
4037 } else if (!strcasecmp(a->argv[3], "off")
4038 && ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
4040 ast_cli(a->fd, "CDR debugging disabled\n");
4041 }
4042 cdr_set_debug_mode(mod_cfg);
4043 ao2_cleanup(mod_cfg);
4044
4045 return CLI_SUCCESS;
4046}
#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 4194 of file cdr.c.

4195{
4196 switch (cmd) {
4197 case CLI_INIT:
4198 e->command = "cdr show active";
4199 e->usage =
4200 "Usage: cdr show active [channel]\n"
4201 " Displays a summary of all Call Detail Records when [channel]\n"
4202 " is omitted; displays all of the Call Detail Records\n"
4203 " currently in flight for a given [channel] when [channel] is\n"
4204 " specified.\n\n"
4205 " Note that this will not display Call Detail Records that\n"
4206 " have already been dispatched to a backend storage, nor for\n"
4207 " channels that are no longer active.\n";
4208 return NULL;
4209 case CLI_GENERATE:
4210 return cli_complete_show(a);
4211 }
4212
4213 if (a->argc > 4) {
4214 return CLI_SHOWUSAGE;
4215 } else if (a->argc < 4) {
4217 } else {
4219 }
4220
4221 return CLI_SUCCESS;
4222}
static void cli_show_channels(struct ast_cli_args *a)
Definition: cdr.c:4070
static char * cli_complete_show(struct ast_cli_args *a)
Complete user input for 'cdr show'.
Definition: cdr.c:4049
static void cli_show_channel(struct ast_cli_args *a)
Definition: cdr.c:4134

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

4225{
4226 struct cdr_beitem *beitem = NULL;
4227 struct module_config *mod_cfg;
4228 int cnt = 0;
4229 long nextbatchtime = 0;
4230
4231 switch (cmd) {
4232 case CLI_INIT:
4233 e->command = "cdr show status";
4234 e->usage =
4235 "Usage: cdr show status\n"
4236 " Displays the Call Detail Record engine system status.\n";
4237 return NULL;
4238 case CLI_GENERATE:
4239 return NULL;
4240 }
4241
4242 if (a->argc > 3) {
4243 return CLI_SHOWUSAGE;
4244 }
4245
4246 mod_cfg = ao2_global_obj_ref(module_configs);
4247 if (!mod_cfg) {
4248 return CLI_FAILURE;
4249 }
4250
4251 ast_cli(a->fd, "\n");
4252 ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
4253 ast_cli(a->fd, "----------------------------------\n");
4254 ast_cli(a->fd, " Logging: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) ? "Enabled" : "Disabled");
4255 ast_cli(a->fd, " Mode: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE) ? "Batch" : "Simple");
4256 if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4257 ast_cli(a->fd, " Log calls by default: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_CHANNEL_DEFAULT_ENABLED) ? "Yes" : "No");
4258 ast_cli(a->fd, " Log unanswered calls: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) ? "Yes" : "No");
4259 ast_cli(a->fd, " Log congestion: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION) ? "Yes" : "No");
4260 ast_cli(a->fd, " Ignore bridging changes: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_STATE_CHANGES) ? "Yes" : "No");
4261 ast_cli(a->fd, " Ignore dial state changes: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_DIAL_CHANGES) ? "Yes" : "No");
4262 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4263 ast_cli(a->fd, "* Batch Mode Settings\n");
4264 ast_cli(a->fd, " -------------------\n");
4265 if (batch)
4266 cnt = batch->size;
4267 if (cdr_sched > -1)
4268 nextbatchtime = ast_sched_when(sched, cdr_sched);
4269 ast_cli(a->fd, " Safe shutdown: %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN) ? "Enabled" : "Disabled");
4270 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");
4271 ast_cli(a->fd, " Current batch size: %d record%s\n", cnt, ESS(cnt));
4272 ast_cli(a->fd, " Maximum batch size: %u record%s\n", mod_cfg->general->batch_settings.size, ESS(mod_cfg->general->batch_settings.size));
4273 ast_cli(a->fd, " Maximum batch time: %u second%s\n", mod_cfg->general->batch_settings.time, ESS(mod_cfg->general->batch_settings.time));
4274 ast_cli(a->fd, " Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
4275 }
4276 ast_cli(a->fd, "* Registered Backends\n");
4277 ast_cli(a->fd, " -------------------\n");
4279 if (AST_RWLIST_EMPTY(&be_list)) {
4280 ast_cli(a->fd, " (none)\n");
4281 } else {
4282 AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
4283 ast_cli(a->fd, " %s%s\n", beitem->name, beitem->suspended ? " (suspended) " : "");
4284 }
4285 }
4287 ast_cli(a->fd, "\n");
4288 }
4289
4290 ao2_cleanup(mod_cfg);
4291 return CLI_SUCCESS;
4292}
static int cdr_sched
Definition: cdr.c:395
@ 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 4294 of file cdr.c.

4295{
4296 struct module_config *mod_cfg;
4297
4298 switch (cmd) {
4299 case CLI_INIT:
4300 e->command = "cdr submit";
4301 e->usage =
4302 "Usage: cdr submit\n"
4303 "Posts all pending batched CDR data to the configured CDR\n"
4304 "backend engine modules.\n";
4305 return NULL;
4306 case CLI_GENERATE:
4307 return NULL;
4308 }
4309 if (a->argc > 2) {
4310 return CLI_SHOWUSAGE;
4311 }
4312
4313 mod_cfg = ao2_global_obj_ref(module_configs);
4314 if (!mod_cfg) {
4315 return CLI_FAILURE;
4316 }
4317
4318 if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4319 ast_cli(a->fd, "Cannot submit CDR batch: CDR engine disabled.\n");
4320 } else if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4321 ast_cli(a->fd, "Cannot submit CDR batch: batch mode not enabled.\n");
4322 } else {
4324 ast_cli(a->fd, "Submitted CDRs to backend engines for processing. This may take a while.\n");
4325 }
4326 ao2_cleanup(mod_cfg);
4327
4328 return CLI_SUCCESS;
4329}

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

2148{
2149 struct cdr_object *cdr;
2152 struct ast_channel_snapshot *peer;
2153 struct cdr_object *it_cdr;
2154 struct ast_json *dial_status_blob;
2155 const char *dial_status = NULL;
2156 int res = 1;
2157
2158 caller = ast_multi_channel_blob_get_channel(payload, "caller");
2159 peer = ast_multi_channel_blob_get_channel(payload, "peer");
2160 if (!peer && !caller) {
2161 return;
2162 }
2163
2164 if (peer && filter_channel_snapshot(peer)) {
2165 return;
2166 }
2167
2168 if (caller && filter_channel_snapshot(caller)) {
2169 return;
2170 }
2171
2172 dial_status_blob = ast_json_object_get(ast_multi_channel_blob_get_json(payload), "dialstatus");
2173 if (dial_status_blob) {
2174 dial_status = ast_json_string_get(dial_status_blob);
2175 }
2176
2177 CDR_DEBUG("Dial %s message for %s, %s: %u.%08u\n",
2178 ast_strlen_zero(dial_status) ? "Begin" : "End",
2179 caller ? caller->base->name : "(none)",
2180 peer ? peer->base->name : "(none)",
2181 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2182 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2183
2184 /* Figure out who is running this show */
2185 if (caller) {
2187 } else {
2189 }
2190 if (!cdr) {
2191 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->base->name : peer->base->name);
2192 ast_assert(0);
2193 return;
2194 }
2195
2196 ao2_lock(cdr);
2197 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2199 if (ast_strlen_zero(dial_status)) {
2200 if (!it_cdr->fn_table->process_dial_begin) {
2201 continue;
2202 }
2204 CDR_DEBUG("%p - Ignoring Dial Begin message\n", it_cdr);
2205 continue;
2206 }
2207 CDR_DEBUG("%p - Processing Dial Begin message for channel %s, peer %s\n",
2208 it_cdr,
2209 caller ? caller->base->name : "(none)",
2210 peer ? peer->base->name : "(none)");
2211 res &= it_cdr->fn_table->process_dial_begin(it_cdr,
2212 caller,
2213 peer);
2214 } else if (dial_status_end(dial_status)) {
2215 if (!it_cdr->fn_table->process_dial_end) {
2216 continue;
2217 }
2219 /* Set the disposition, and do nothing else. */
2220 it_cdr->disposition = dial_status_to_disposition(dial_status);
2221 CDR_DEBUG("%p - Setting disposition and that's it (%s)\n", it_cdr, dial_status);
2222 continue;
2223 }
2224 CDR_DEBUG("%p - Processing Dial End message for channel %s, peer %s\n",
2225 it_cdr,
2226 caller ? caller->base->name : "(none)",
2227 peer ? peer->base->name : "(none)");
2228 it_cdr->fn_table->process_dial_end(it_cdr,
2229 caller,
2230 peer,
2231 dial_status);
2232 }
2233 }
2234
2235 /* If we're ignoring dial changes, don't allow multiple CDRs for this channel. */
2236 if (!dial_changes_ignored) {
2237 /* If no CDR handled a dial begin message, make a new one */
2238 if (res && ast_strlen_zero(dial_status)) {
2239 struct cdr_object *new_cdr;
2240
2242 if (new_cdr) {
2243 new_cdr->fn_table->process_dial_begin(new_cdr, caller, peer);
2244 }
2245 }
2246 }
2247
2248 ao2_unlock(cdr);
2249 ao2_cleanup(cdr);
2250}
static int dial_changes_ignored
Definition: cdr.c:250
static int dial_status_end(const char *dialstatus)
Definition: cdr.c:2132
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:522
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:504

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

2820{
2822 struct ast_channel_snapshot *channel = payload->parkee;
2823 struct cdr_object *cdr;
2824 int unhandled = 1;
2825 struct cdr_object *it_cdr;
2826
2827 /* Anything other than getting parked will be handled by other updates */
2828 if (payload->event_type != PARKED_CALL) {
2829 return;
2830 }
2831
2832 /* No one got parked? */
2833 if (!channel) {
2834 return;
2835 }
2836
2837 if (filter_channel_snapshot(channel)) {
2838 return;
2839 }
2840
2841 CDR_DEBUG("Parked Call message for channel %s: %u.%08u\n",
2842 channel->base->name,
2843 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2844 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2845
2847 if (!cdr) {
2848 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2849 ast_assert(0);
2850 return;
2851 }
2852
2853 ao2_lock(cdr);
2854
2855 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2857 if (it_cdr->fn_table->process_parked_channel) {
2858 unhandled &= it_cdr->fn_table->process_parked_channel(it_cdr, payload);
2859 }
2860 }
2861
2862 if (unhandled) {
2863 /* Nothing handled the messgae - we need a new one! */
2864 struct cdr_object *new_cdr;
2865
2867 if (new_cdr) {
2868 /* As the new CDR is created in the single state, it is guaranteed
2869 * to have a function for the parked call message and will handle
2870 * the message */
2871 new_cdr->fn_table->process_parked_channel(new_cdr, payload);
2872 }
2873 }
2874
2875 ao2_unlock(cdr);
2876
2877 ao2_cleanup(cdr);
2878}
@ 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:588

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

2658{
2659 int res = 1;
2660 struct cdr_object *it_cdr;
2661 struct cdr_object *new_cdr;
2662
2663 ao2_lock(cdr);
2664
2665 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2666 it_cdr->lastevent = *event_time;
2667
2669 res &= it_cdr->fn_table->process_parking_bridge_enter(it_cdr, bridge, channel);
2670 }
2671 if (it_cdr->fn_table->process_party_a) {
2672 CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
2673 channel->base->name);
2674 it_cdr->fn_table->process_party_a(it_cdr, channel);
2675 }
2676 }
2677
2678 if (res) {
2679 /* No one handled it - we need a new one! */
2680 new_cdr = cdr_object_create_and_append(cdr, event_time);
2681 if (new_cdr) {
2682 /* Let the single state transition us to Parked */
2684 new_cdr->fn_table->process_parking_bridge_enter(new_cdr, bridge, channel);
2685 }
2686 }
2687 ao2_unlock(cdr);
2688}
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:561

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

2700{
2702 struct cdr_object *it_cdr;
2703 struct cdr_object *new_cdr;
2704 struct cdr_object *handled_cdr = NULL;
2705
2706 ao2_lock(cdr);
2707
2708try_again:
2709 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2710 it_cdr->lastevent = *event_time;
2711
2712 if (it_cdr->fn_table->process_party_a) {
2713 CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
2714 channel->base->name);
2715 it_cdr->fn_table->process_party_a(it_cdr, channel);
2716 }
2717
2718 /* Notify all states that they have entered a bridge */
2719 if (it_cdr->fn_table->process_bridge_enter) {
2720 CDR_DEBUG("%p - Processing bridge enter for %s\n", it_cdr,
2721 channel->base->name);
2722 result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
2723 switch (result) {
2725 /* Fall through */
2727 if (!handled_cdr) {
2728 handled_cdr = it_cdr;
2729 }
2730 break;
2732 /* Pass */
2733 break;
2735 /* We didn't win on any - end this CDR. If someone else comes in later
2736 * that is Party B to this CDR, it can re-activate this CDR.
2737 */
2738 if (!handled_cdr) {
2739 handled_cdr = it_cdr;
2740 }
2742 break;
2743 }
2744 }
2745 }
2746
2747 /* Create the new matchings, but only for either:
2748 * * The first CDR in the chain that handled it. This avoids issues with
2749 * forked CDRs.
2750 * * If no one handled it, the last CDR in the chain. This would occur if
2751 * a CDR joined a bridge and it wasn't Party A for anyone. We still need
2752 * to make pairings with everyone in the bridge.
2753 */
2754 if (handled_cdr) {
2755 handle_bridge_pairings(handled_cdr, bridge);
2756 } else {
2757 /* Nothing handled it - we need a new one! */
2758 new_cdr = cdr_object_create_and_append(cdr, event_time);
2759 if (new_cdr) {
2760 /* This is guaranteed to succeed: the new CDR is created in the single state
2761 * and will be able to handle the bridge enter message
2762 */
2763 goto try_again;
2764 }
2765 }
2766 ao2_unlock(cdr);
2767}
process_bridge_enter_results
Return types for process_bridge_enter functions.
Definition: cdr.c:433
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:2628
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 3817 of file cdr.c.

3818{
3819 /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
3820 if (!(batch = ast_malloc(sizeof(*batch))))
3821 return -1;
3822
3823 reset_batch();
3824
3825 return 0;
3826}
#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 4603 of file cdr.c.

4604{
4605 struct module_config *mod_cfg = NULL;
4606 if (process_config(0)) {
4608 }
4609
4610 cdr_topic = stasis_topic_create("cdr:aggregator");
4611 if (!cdr_topic) {
4613 }
4614
4616 if (!stasis_router) {
4618 }
4621
4622 if (STASIS_MESSAGE_TYPE_INIT(cdr_sync_message_type)) {
4624 }
4625
4626 mod_cfg = ao2_global_obj_ref(module_configs);
4627
4629
4630 /* Always process dial messages, because even if we ignore most of it, we do want the dial status for the disposition. */
4632 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_DIAL_CHANGES)) {
4634 } else {
4636 CDR_DEBUG("Dial messages will be mostly ignored\n");
4637 }
4638
4639 /* If explicitly instructed to ignore call state changes, then ignore bridging events, parking, etc. */
4640 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_STATE_CHANGES)) {
4644 } else {
4645 CDR_DEBUG("All bridge and parking messages will be ignored\n");
4646 }
4647
4649
4650 if (mod_cfg) {
4651 ao2_cleanup(mod_cfg);
4652 } else {
4653 ast_log(LOG_WARNING, "Unable to obtain CDR configuration during module load?\n");
4654 }
4655
4658 if (!active_cdrs_master) {
4660 }
4662
4665 if (!active_cdrs_all) {
4667 }
4669
4671 if (!sched) {
4672 ast_log(LOG_ERROR, "Unable to create schedule context.\n");
4674 }
4675
4678
4680}
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:2818
static int process_config(int reload)
Definition: cdr.c:4422
static void cdr_all_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: cdr.c:4553
static int cdr_all_hash_fn(const void *obj, const int flags)
Definition: cdr.c:932
static int cdr_master_cmp_fn(void *obj, void *arg, int flags)
Definition: cdr.c:898
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:2471
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:2333
static void handle_bridge_enter_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cdr.c:2776
static void handle_cdr_sync_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for a synchronization message.
Definition: cdr.c:2886
static void cdr_master_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: cdr.c:4528
static int cdr_all_cmp_fn(void *obj, void *arg, int flags)
Definition: cdr.c:956
static void handle_dial_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for Stasis-Core dial messages.
Definition: cdr.c:2147
static void cdr_engine_shutdown(void)
Definition: cdr.c:4470
static int cdr_master_hash_fn(const void *obj, const int flags)
Definition: cdr.c:874
#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:618
#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 342 of file cdr.c.

343{
344 struct module_config *mod_cfg;
346
347 mod_cfg = ao2_alloc(sizeof(*mod_cfg), module_config_destructor);
348 if (!mod_cfg) {
349 return NULL;
350 }
351
352 cdr_config = ao2_alloc(sizeof(*cdr_config), NULL);
353 if (!cdr_config) {
354 ao2_ref(cdr_config, -1);
355 return NULL;
356 }
357 mod_cfg->general = cdr_config;
358
359 return mod_cfg;
360}
static void module_config_destructor(void *obj)
Dispose of a module config object.
Definition: cdr.c:331
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 331 of file cdr.c.

332{
333 struct module_config *cfg = obj;
334
335 if (!cfg) {
336 return;
337 }
338 ao2_ref(cfg->general, -1);
339}

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

319{
320 struct module_config *mod_cfg;
321
322 mod_cfg = ao2_global_obj_ref(module_configs);
323 if (!mod_cfg) {
324 return;
325 }
326 cdr_set_debug_mode(mod_cfg);
327 ao2_cleanup(mod_cfg);
328}

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

2076{
2077 if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)) {
2078 return 1;
2079 }
2081
2082 return 0;
2083}

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

3588{
3589 struct module_config *mod_cfg;
3590 struct cdr_beitem *i;
3591
3592 mod_cfg = ao2_global_obj_ref(module_configs);
3593 if (!mod_cfg) {
3594 return;
3595 }
3596
3597 for (; cdr ; cdr = cdr->next) {
3598 /* For people, who don't want to see unanswered single-channel events */
3599 if (!ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) &&
3602 ast_debug(1, "Skipping CDR for %s since we weren't answered\n", cdr->channel);
3603 continue;
3604 }
3605
3606 /* Modify CDR's */
3608 AST_RWLIST_TRAVERSE(&mo_list, i, list) {
3609 i->be(cdr);
3610 }
3612
3614 continue;
3615 }
3617 AST_RWLIST_TRAVERSE(&be_list, i, list) {
3618 if (!i->suspended) {
3619 i->be(cdr);
3620 }
3621 }
3623 }
3624 ao2_cleanup(mod_cfg);
3625}
@ 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 4422 of file cdr.c.

4423{
4424 if (!reload) {
4425 if (aco_info_init(&cfg_info)) {
4426 return 1;
4427 }
4428
4443 }
4444
4445 if (aco_process_config(&cfg_info, reload) == ACO_PROCESS_ERROR) {
4446 struct module_config *mod_cfg;
4447
4448 if (reload) {
4449 return 1;
4450 }
4451
4452 /* If we couldn't process the configuration and this wasn't a reload,
4453 * create a default config
4454 */
4455 mod_cfg = module_config_alloc();
4456 if (!mod_cfg
4457 || aco_set_defaults(&general_option, "general", mod_cfg->general)) {
4458 ao2_cleanup(mod_cfg);
4459 return 1;
4460 }
4461 ast_log(LOG_NOTICE, "Failed to process CDR configuration; using defaults\n");
4462 ao2_global_obj_replace_unref(module_configs, mod_cfg);
4463 cdr_set_debug_mode(mod_cfg);
4464 ao2_cleanup(mod_cfg);
4465 }
4466
4467 return 0;
4468}
#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:237
#define MAX_BATCH_SIZE
Definition: cdr.c:238
#define DEFAULT_BATCHMODE
Definition: cdr.c:228
#define DEFAULT_IGNORE_STATE_CHANGES
Definition: cdr.c:234
#define DEFAULT_UNANSWERED
Definition: cdr.c:229
static struct aco_type general_option
The type definition for general options.
Definition: cdr.c:272
#define MAX_BATCH_TIME
Definition: cdr.c:240
static struct aco_type * general_options[]
Definition: cdr.c:316
#define DEFAULT_INITIATED_SECONDS
Definition: cdr.c:232
#define DEFAULT_IGNORE_DIAL_CHANGES
Definition: cdr.c:235
#define DEFAULT_BATCH_SAFE_SHUTDOWN
Definition: cdr.c:242
#define DEFAULT_BATCH_TIME
Definition: cdr.c:239
#define DEFAULT_BATCH_SCHEDULER_ONLY
Definition: cdr.c:241
#define DEFAULT_CHANNEL_ENABLED
Definition: cdr.c:233
#define DEFAULT_ENABLED
Definition: cdr.c:227
static void * module_config_alloc(void)
Create a new module config object.
Definition: cdr.c:342
#define DEFAULT_END_BEFORE_H_EXTEN
Definition: cdr.c:231
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 4722 of file cdr.c.

4723{
4724 struct module_config *old_mod_cfg;
4725 struct module_config *mod_cfg;
4726
4727 old_mod_cfg = ao2_global_obj_ref(module_configs);
4728
4729 if (!old_mod_cfg || process_config(1)) {
4730 ao2_cleanup(old_mod_cfg);
4731 return -1;
4732 }
4733
4734 mod_cfg = ao2_global_obj_ref(module_configs);
4735 if (!mod_cfg
4736 || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)
4737 || !ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4738 /* If batch mode used to be enabled, finalize the batch */
4739 if (ast_test_flag(&old_mod_cfg->general->settings, CDR_BATCHMODE)) {
4741 }
4742 }
4743 ao2_cleanup(mod_cfg);
4744
4745 ao2_cleanup(old_mod_cfg);
4747}

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

3810{
3811 batch->size = 0;
3812 batch->head = NULL;
3813 batch->tail = NULL;
3814}

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

1304{
1305 struct ast_var_t *newvariable;
1306
1307 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1308 if (!strcasecmp(ast_var_name(newvariable), name)) {
1310 ast_var_delete(newvariable);
1311 break;
1312 }
1313 }
1315
1316 if (value && (newvariable = ast_var_assign(name, value))) {
1317 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1318 }
1319}
#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 1735 of file cdr.c.

1737{
1738 struct cdr_object_snapshot *party_a;
1739
1740 /* Don't match on ourselves */
1741 if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
1742 return 1;
1743 }
1744
1745 /* Try the candidate CDR's Party A first */
1746 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
1747 if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
1748 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
1749 cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name);
1750 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
1751 cdr_all_relink(cdr);
1752 if (!cand_cdr->party_b.snapshot) {
1753 /* We just stole them - finalize their CDR. Note that this won't
1754 * transition their state, it just sets the end time and the
1755 * disposition - if we need to re-activate them later, we can.
1756 */
1757 cdr_object_finalize(cand_cdr);
1758 }
1759 return 0;
1760 }
1761
1762 /* Try their Party B, unless it's us */
1763 if (!cand_cdr->party_b.snapshot
1764 || !strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name)) {
1765 return 1;
1766 }
1767 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b);
1768 if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
1769 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
1770 cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name);
1771 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
1772 cdr_all_relink(cdr);
1773 return 0;
1774 }
1775
1776 return 1;
1777}

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

1683{
1684 cdr->start = cdr->lastevent;
1686}

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

1780{
1781 struct ao2_iterator it_cdrs;
1782 char *channel_id;
1783 int success = 0;
1784
1785 ast_string_field_set(cdr, bridge, bridge->uniqueid);
1786
1787 if (ao2_container_count(bridge->channels) == 1) {
1788 /* No one in the bridge yet but us! */
1791 }
1792
1793 for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
1794 !success && (channel_id = ao2_iterator_next(&it_cdrs));
1795 ao2_ref(channel_id, -1)) {
1796 struct cdr_object *cand_cdr_master;
1797 struct cdr_object *cand_cdr;
1798
1799 cand_cdr_master = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
1800 if (!cand_cdr_master) {
1801 continue;
1802 }
1803
1804 ao2_lock(cand_cdr_master);
1805 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
1806 /* Skip any records that are not in a bridge or in this bridge.
1807 * I'm not sure how that would happen, but it pays to be careful. */
1808 if (cand_cdr->fn_table != &bridge_state_fn_table ||
1809 strcmp(cdr->bridge, cand_cdr->bridge)) {
1810 continue;
1811 }
1812
1813 if (single_state_bridge_enter_comparison(cdr, cand_cdr)) {
1814 continue;
1815 }
1816 /* We successfully got a party B - break out */
1817 success = 1;
1818 break;
1819 }
1820 ao2_unlock(cand_cdr_master);
1821 ao2_cleanup(cand_cdr_master);
1822 }
1823 ao2_iterator_destroy(&it_cdrs);
1824
1825 /* We always transition state, even if we didn't get a peer */
1827
1828 /* Success implies that we have a Party B */
1829 if (success) {
1831 }
1832
1834}
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:1735

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

1697{
1698 if (caller && !strcasecmp(cdr->party_a.snapshot->base->name, caller->base->name)) {
1699 base_process_party_a(cdr, caller);
1700 CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
1701 cdr->party_a.snapshot->base->name);
1702 cdr_object_swap_snapshot(&cdr->party_b, peer);
1703 cdr_all_relink(cdr);
1704 CDR_DEBUG("%p - Updated Party B %s snapshot\n", cdr,
1705 cdr->party_b.snapshot->base->name);
1706
1707 /* If we have two parties, lock the application that caused the
1708 * two parties to be associated. This prevents mid-call event
1709 * gosubs from perturbing the CDR application/data
1710 */
1712 } else if (!strcasecmp(cdr->party_a.snapshot->base->name, peer->base->name)) {
1713 /* We're the entity being dialed, i.e., outbound origination */
1714 base_process_party_a(cdr, peer);
1715 CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
1716 cdr->party_a.snapshot->base->name);
1717 }
1718
1720 return 0;
1721}

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

1837{
1839 return 0;
1840}

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

1689{
1690 /* This should never happen! */
1692 ast_assert(0);
1693 return;
1694}

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

1191{
1192 /* If we ignore hangup logic, don't indicate that we're executing anything new */
1195 return 0;
1196 }
1197
1198 /* When Party A is originated to an application and the application exits, the stack
1199 * will attempt to clear the application and restore the dummy originate application
1200 * of "AppDialX". Ignore application changes to AppDialX as a result.
1201 */
1202 if (strcmp(new_snapshot->dialplan->appl, old_snapshot->dialplan->appl)
1203 && strncasecmp(new_snapshot->dialplan->appl, "appdial", 7)
1204 && (strcmp(new_snapshot->dialplan->context, old_snapshot->dialplan->context)
1205 || strcmp(new_snapshot->dialplan->exten, old_snapshot->dialplan->exten)
1206 || new_snapshot->dialplan->priority != old_snapshot->dialplan->priority)) {
1207 return 1;
1208 }
1209
1210 return 0;
1211}

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

1221{
1222 return (ast_test_flag(&snapshot->flags, AST_FLAG_OUTGOING)
1223 && !(ast_test_flag(&snapshot->flags, AST_FLAG_ORIGINATED)));
1224}
@ 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 3904 of file cdr.c.

3905{
3906 /* Prevent two deletes from happening at the same time */
3908 /* this is okay since we are not being called from within the scheduler */
3910 /* schedule the submission to occur ASAP (1 ms) */
3913
3914 /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
3918}
static int submit_scheduled_batch(const void *data)
Definition: cdr.c:3883
static ast_mutex_t cdr_sched_lock
Definition: cdr.c:396
#define ast_cond_signal(cond)
Definition: lock.h:203
#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 3883 of file cdr.c.

3884{
3885 struct module_config *mod_cfg;
3886 int nextms;
3887
3889
3890 mod_cfg = ao2_global_obj_ref(module_configs);
3891 if (!mod_cfg) {
3892 return 0;
3893 }
3894
3895 /* Calculate the next scheduled interval */
3896 nextms = mod_cfg->general->batch_settings.time * 1000;
3897
3898 ao2_cleanup(mod_cfg);
3899
3900 return nextms;
3901}

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

4597{
4599
4600 return 0;
4601}

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 4756 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 410 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 4756 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 701 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 416 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 400 of file cdr.c.

Referenced by cdr_detach(), and cdr_submit_batch().

◆ cdr_debug_enabled

int cdr_debug_enabled
static

Definition at line 249 of file cdr.c.

◆ cdr_pending_cond

ast_cond_t cdr_pending_cond
static

Definition at line 404 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 403 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 3224 of file cdr.c.

Referenced by ast_cdr_serialize_variables(), and ast_cdr_setvar().

◆ cdr_sched

int cdr_sched = -1
static

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

Referenced by start_batch_mode().

◆ cdr_thread

pthread_t cdr_thread = AST_PTHREADT_NULL
static

Definition at line 397 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 425 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 419 of file cdr.c.

Referenced by create_subscriptions(), and destroy_subscriptions().

◆ cli_commands

struct ast_cli_entry cli_commands[]
static

Definition at line 4331 of file cdr.c.

Referenced by cdr_engine_shutdown(), and load_module().

◆ dial_changes_ignored

int dial_changes_ignored
static

Definition at line 250 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 646 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 679 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 272 of file cdr.c.

Referenced by process_config().

◆ general_options

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

Definition at line 316 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 391 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 281 of file cdr.c.

◆ ignore_option

struct aco_type ignore_option
static

Definition at line 294 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:294
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.

The file definition.

Definition at line 306 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 720 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 422 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 394 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 615 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 413 of file cdr.c.

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