Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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_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 []
 
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:224

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

Definition at line 219 of file cdr.c.

◆ DEFAULT_BATCH_SAFE_SHUTDOWN

#define DEFAULT_BATCH_SAFE_SHUTDOWN   "1"

Definition at line 217 of file cdr.c.

◆ DEFAULT_BATCH_SCHEDULER_ONLY

#define DEFAULT_BATCH_SCHEDULER_ONLY   "0"

Definition at line 216 of file cdr.c.

◆ DEFAULT_BATCH_SIZE

#define DEFAULT_BATCH_SIZE   "100"

Definition at line 212 of file cdr.c.

◆ DEFAULT_BATCH_TIME

#define DEFAULT_BATCH_TIME   "300"

Definition at line 214 of file cdr.c.

◆ DEFAULT_BATCHMODE

#define DEFAULT_BATCHMODE   "0"

Definition at line 205 of file cdr.c.

◆ DEFAULT_CHANNEL_ENABLED

#define DEFAULT_CHANNEL_ENABLED   "1"

Definition at line 210 of file cdr.c.

◆ DEFAULT_CONGESTION

#define DEFAULT_CONGESTION   "0"

Definition at line 207 of file cdr.c.

◆ DEFAULT_ENABLED

#define DEFAULT_ENABLED   "1"

Definition at line 204 of file cdr.c.

◆ DEFAULT_END_BEFORE_H_EXTEN

#define DEFAULT_END_BEFORE_H_EXTEN   "1"

Definition at line 208 of file cdr.c.

◆ DEFAULT_INITIATED_SECONDS

#define DEFAULT_INITIATED_SECONDS   "0"

Definition at line 209 of file cdr.c.

◆ DEFAULT_UNANSWERED

#define DEFAULT_UNANSWERED   "0"

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

◆ MAX_BATCH_TIME

#define MAX_BATCH_TIME   86400

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

407  {
408  /*!
409  * The CDR was the only party in the bridge.
410  */
412  /*!
413  * The CDR was able to obtain a Party B from some other party already in the bridge
414  */
416  /*!
417  * The CDR was not able to obtain a Party B
418  */
420  /*!
421  * This CDR can't handle a bridge enter message and a new CDR needs to be created
422  */
424 };
@ BRIDGE_ENTER_ONLY_PARTY
Definition: cdr.c:411
@ BRIDGE_ENTER_NO_PARTY_B
Definition: cdr.c:419
@ BRIDGE_ENTER_NEED_CDR
Definition: cdr.c:423
@ BRIDGE_ENTER_OBTAINED_PARTY_B
Definition: cdr.c:415

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 4671 of file cdr.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

3445 {
3446  struct ast_cdr *x;
3447 
3448  x = ast_calloc(1, sizeof(*x));
3449  return x;
3450 }
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
Responsible for call detail data.
Definition: cdr.h:277

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

2889 {
2890  int success = -1;
2891  struct cdr_beitem *i = NULL;
2892 
2894  AST_RWLIST_TRAVERSE(&be_list, i, list) {
2895  if (!strcasecmp(name, i->name)) {
2896  ast_debug(3, "Suspending CDR backend %s\n", i->name);
2897  i->suspended = 1;
2898  success = 0;
2899  }
2900  }
2902 
2903  return success;
2904 }
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:346
Registration object for CDR backends.
Definition: cdr.c:337
char name[20]
Definition: cdr.c:338

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

2907 {
2908  int success = -1;
2909  struct cdr_beitem *i = NULL;
2910 
2912  AST_RWLIST_TRAVERSE(&be_list, i, list) {
2913  if (!strcasecmp(name, i->name)) {
2914  ast_debug(3, "Unsuspending CDR backend %s\n", i->name);
2915  i->suspended = 0;
2916  success = 0;
2917  }
2918  }
2920 
2921  return success;
2922 }

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

3598 {
3599  struct cdr_object *cdr;
3600  struct cdr_object *it_cdr;
3601 
3602  cdr = cdr_object_get_by_name(channel_name);
3603  if (!cdr) {
3604  return -1;
3605  }
3606 
3607  ao2_lock(cdr);
3608  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3609  if (it_cdr->fn_table == &finalized_state_fn_table) {
3610  continue;
3611  }
3612  ast_clear_flag(&it_cdr->flags, option);
3613  }
3614  ao2_unlock(cdr);
3615 
3616  ao2_cleanup(cdr);
3617  return 0;
3618 }
#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:710
static struct cdr_object * cdr_object_get_by_name(const char *name)
Definition: cdr.c:3334
An in-memory representation of an active CDR.
Definition: cdr.c:728
struct cdr_object_fn_table * fn_table
Definition: cdr.c:731
struct cdr_object * next
Definition: cdr.c:751
struct ast_flags flags
Definition: cdr.c:739
#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 appcdr_callback(), 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 3452 of file cdr.c.

3453 {
3454  switch (disposition) {
3455  case AST_CDR_NULL:
3456  return "NO ANSWER"; /* by default, for backward compatibility */
3457  case AST_CDR_NOANSWER:
3458  return "NO ANSWER";
3459  case AST_CDR_FAILED:
3460  return "FAILED";
3461  case AST_CDR_BUSY:
3462  return "BUSY";
3463  case AST_CDR_ANSWERED:
3464  return "ANSWERED";
3465  case AST_CDR_CONGESTION:
3466  return "CONGESTION";
3467  }
3468  return "UNKNOWN";
3469 }
@ AST_CDR_CONGESTION
Definition: cdr.h:260
@ AST_CDR_NULL
Definition: cdr.h:256
@ AST_CDR_NOANSWER
Definition: cdr.h:255
@ AST_CDR_ANSWERED
Definition: cdr.h:259
@ AST_CDR_BUSY
Definition: cdr.h:258
@ AST_CDR_FAILED
Definition: cdr.h:257

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

3021 {
3022  struct ast_cdr *newcdr;
3023 
3024  if (!cdr) {
3025  return NULL;
3026  }
3027  newcdr = ast_cdr_alloc();
3028  if (!newcdr) {
3029  return NULL;
3030  }
3031 
3032  *newcdr = *cdr;
3034  copy_variables(&newcdr->varshead, &cdr->varshead);
3035  newcdr->next = NULL;
3036 
3037  return newcdr;
3038 }
struct ast_cdr * ast_cdr_alloc(void)
Allocate a CDR record.
Definition: cdr.c:3444
static int copy_variables(struct varshead *to_list, struct varshead *from_list)
Copy variables from one list to another.
Definition: cdr.c:762
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
struct ast_cdr * next
Definition: cdr.h:326
struct varshead varshead
Definition: cdr.h:324

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

4598 {
4599  RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
4600 
4601  /* Since this is called explicitly during process shutdown, we might not have ever
4602  * been initialized. If so, the config object will be NULL.
4603  */
4604  if (!mod_cfg) {
4605  return;
4606  }
4607 
4608  if (cdr_sync_message_type()) {
4609  void *payload;
4610  struct stasis_message *message;
4611 
4612  if (!stasis_router) {
4613  return;
4614  }
4615 
4616  /* Make sure we have the needed items */
4617  payload = ao2_alloc(sizeof(*payload), NULL);
4618  if (!payload) {
4619  return;
4620  }
4621 
4622  ast_debug(1, "CDR Engine termination request received; waiting on messages...\n");
4623 
4624  message = stasis_message_create(cdr_sync_message_type(), payload);
4625  if (message) {
4627  }
4629  ao2_cleanup(payload);
4630  }
4631 
4632  if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4633  cdr_submit_batch(ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN));
4634  }
4635 }
#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:387
static void cdr_submit_batch(int shutdown)
Definition: cdr.c:3788
@ CDR_BATCHMODE
Definition: cdr.h:221
@ BATCH_MODE_SAFE_SHUTDOWN
Definition: cdr.h:233
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:238
#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:936

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

3660 {
3661  RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
3662  struct cdr_object *new_cdr;
3663  struct cdr_object *it_cdr;
3664  struct cdr_object *cdr_obj;
3665 
3666  if (!cdr) {
3667  return -1;
3668  }
3669 
3670  {
3671  SCOPED_AO2LOCK(lock, cdr);
3672  struct timeval now = ast_tvnow();
3673 
3674  cdr_obj = cdr->last;
3675  if (cdr_obj->fn_table == &finalized_state_fn_table) {
3676  /* If the last CDR in the chain is finalized, don't allow a fork -
3677  * things are already dying at this point
3678  */
3679  return -1;
3680  }
3681 
3682  /* Copy over the basic CDR information. The Party A information is
3683  * copied over automatically as part of the append
3684  */
3685  ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
3686  new_cdr = cdr_object_create_and_append(cdr, &now);
3687  if (!new_cdr) {
3688  return -1;
3689  }
3690  new_cdr->fn_table = cdr_obj->fn_table;
3691  ast_string_field_set(new_cdr, bridge, cdr->bridge);
3692  ast_string_field_set(new_cdr, appl, cdr->appl);
3693  ast_string_field_set(new_cdr, data, cdr->data);
3694  ast_string_field_set(new_cdr, context, cdr->context);
3695  ast_string_field_set(new_cdr, exten, cdr->exten);
3696  new_cdr->flags = cdr->flags;
3697  /* Explicitly clear the AST_CDR_LOCK_APP flag - we want
3698  * the application to be changed on the new CDR if the
3699  * dialplan demands it
3700  */
3702 
3703  /* If there's a Party B, copy it over as well */
3704  if (cdr_obj->party_b.snapshot) {
3705  new_cdr->party_b.snapshot = cdr_obj->party_b.snapshot;
3706  ao2_ref(new_cdr->party_b.snapshot, +1);
3707  cdr_all_relink(new_cdr);
3708  strcpy(new_cdr->party_b.userfield, cdr_obj->party_b.userfield);
3709  new_cdr->party_b.flags = cdr_obj->party_b.flags;
3711  copy_variables(&new_cdr->party_b.variables, &cdr_obj->party_b.variables);
3712  }
3713  }
3714  new_cdr->start = cdr_obj->start;
3715  new_cdr->answer = cdr_obj->answer;
3716  new_cdr->lastevent = ast_tvnow();
3717 
3718  /* Modify the times based on the flags passed in */
3720  && new_cdr->party_a.snapshot->state == AST_STATE_UP) {
3721  new_cdr->answer = ast_tvnow();
3722  }
3724  new_cdr->answer = ast_tvnow();
3725  new_cdr->start = ast_tvnow();
3726  }
3727 
3728  /* Create and append, by default, copies over the variables */
3730  free_variables(&new_cdr->party_a.variables);
3731  }
3732 
3733  /* Finalize any current CDRs */
3735  for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->next) {
3736  if (it_cdr->fn_table == &finalized_state_fn_table) {
3737  continue;
3738  }
3739  /* Force finalization on the CDR. This will bypass any checks for
3740  * end before 'h' extension.
3741  */
3742  cdr_object_finalize(it_cdr);
3744  }
3745  }
3746  }
3747 
3748  return 0;
3749 }
ast_mutex_t lock
Definition: app_meetme.c:1093
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static void cdr_object_finalize(struct cdr_object *cdr)
Finalize a CDR.
Definition: cdr.c:1453
static void cdr_all_relink(struct cdr_object *cdr)
Definition: cdr.c:964
static void free_variables(struct varshead *headp)
Delete all variables from a variable list.
Definition: cdr.c:793
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:838
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:1090
@ AST_CDR_LOCK_APP
Definition: cdr.h:248
@ AST_CDR_FLAG_FINALIZE
Definition: cdr.h:245
@ AST_CDR_FLAG_KEEP_VARS
Definition: cdr.h:241
@ AST_CDR_FLAG_RESET
Definition: cdr.h:247
@ AST_CDR_FLAG_SET_ANSWER
Definition: cdr.h:246
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
@ AST_STATE_UP
Definition: channelstate.h:42
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
#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:722
struct varshead variables
Definition: cdr.c:724
struct ast_channel_snapshot * snapshot
Definition: cdr.c:721
unsigned int flags
Definition: cdr.c:723
struct timeval answer
Definition: cdr.c:735
struct cdr_object_snapshot party_a
Definition: cdr.c:729
struct timeval lastevent
Definition: cdr.c:737
struct cdr_object * last
Definition: cdr.c:752
struct timeval start
Definition: cdr.c:734
struct cdr_object_snapshot party_b
Definition: cdr.c:730
static struct test_options options
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:157

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(), ast_channel_snapshot::base, cdr_object::bridge, cdr_all_relink(), cdr_object_create_and_append(), cdr_object_finalize(), cdr_object_get_by_name(), cdr_object_transition_state(), context, cdr_object::context, copy_variables(), cdr_object::data, exten, cdr_object::exten, finalized_state_fn_table, cdr_object_snapshot::flags, cdr_object::flags, cdr_object::fn_table, free_variables(), cdr_object::last, cdr_object::lastevent, lock, ast_channel_snapshot_base::name, 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 3072 of file cdr.c.

3073 {
3074  const char *fmt = "%Y-%m-%d %T";
3075  const char *varbuf;
3076 
3077  if (!cdr) {
3078  return;
3079  }
3080 
3081  *ret = NULL;
3082 
3083  if (!strcasecmp(name, "clid")) {
3084  ast_copy_string(workspace, cdr->clid, workspacelen);
3085  } else if (!strcasecmp(name, "src")) {
3086  ast_copy_string(workspace, cdr->src, workspacelen);
3087  } else if (!strcasecmp(name, "dst")) {
3088  ast_copy_string(workspace, cdr->dst, workspacelen);
3089  } else if (!strcasecmp(name, "dcontext")) {
3090  ast_copy_string(workspace, cdr->dcontext, workspacelen);
3091  } else if (!strcasecmp(name, "channel")) {
3092  ast_copy_string(workspace, cdr->channel, workspacelen);
3093  } else if (!strcasecmp(name, "dstchannel")) {
3094  ast_copy_string(workspace, cdr->dstchannel, workspacelen);
3095  } else if (!strcasecmp(name, "lastapp")) {
3096  ast_copy_string(workspace, cdr->lastapp, workspacelen);
3097  } else if (!strcasecmp(name, "lastdata")) {
3098  ast_copy_string(workspace, cdr->lastdata, workspacelen);
3099  } else if (!strcasecmp(name, "start")) {
3100  cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
3101  } else if (!strcasecmp(name, "answer")) {
3102  cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
3103  } else if (!strcasecmp(name, "end")) {
3104  cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
3105  } else if (!strcasecmp(name, "duration")) {
3106  snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
3107  } else if (!strcasecmp(name, "billsec")) {
3108  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);
3109  } else if (!strcasecmp(name, "disposition")) {
3110  if (raw) {
3111  snprintf(workspace, workspacelen, "%ld", cdr->disposition);
3112  } else {
3113  ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
3114  }
3115  } else if (!strcasecmp(name, "amaflags")) {
3116  if (raw) {
3117  snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
3118  } else {
3119  ast_copy_string(workspace, ast_channel_amaflags2string(cdr->amaflags), workspacelen);
3120  }
3121  } else if (!strcasecmp(name, "accountcode")) {
3122  ast_copy_string(workspace, cdr->accountcode, workspacelen);
3123  } else if (!strcasecmp(name, "peeraccount")) {
3124  ast_copy_string(workspace, cdr->peeraccount, workspacelen);
3125  } else if (!strcasecmp(name, "uniqueid")) {
3126  ast_copy_string(workspace, cdr->uniqueid, workspacelen);
3127  } else if (!strcasecmp(name, "linkedid")) {
3128  ast_copy_string(workspace, cdr->linkedid, workspacelen);
3129  } else if (!strcasecmp(name, "userfield")) {
3130  ast_copy_string(workspace, cdr->userfield, workspacelen);
3131  } else if (!strcasecmp(name, "sequence")) {
3132  snprintf(workspace, workspacelen, "%d", cdr->sequence);
3133  } else if ((varbuf = cdr_format_var_internal(cdr, name))) {
3134  ast_copy_string(workspace, varbuf, workspacelen);
3135  } else {
3136  workspace[0] = '\0';
3137  }
3138 
3139  if (!ast_strlen_zero(workspace)) {
3140  *ret = workspace;
3141  }
3142 }
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3452
static void cdr_get_tv(struct timeval when, const char *fmt, char *buf, int bufsize)
Definition: cdr.c:3057
static const char * cdr_format_var_internal(struct ast_cdr *cdr, const char *name)
Definition: cdr.c:3040
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4408
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:406
char dstchannel[AST_MAX_EXTENSION]
Definition: cdr.h:289
long int disposition
Definition: cdr.h:305
char lastdata[AST_MAX_EXTENSION]
Definition: cdr.h:293
char linkedid[AST_MAX_UNIQUEID]
Definition: cdr.h:317
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.h:319
long int billsec
Definition: cdr.h:303
struct timeval answer
Definition: cdr.h:297
char channel[AST_MAX_EXTENSION]
Definition: cdr.h:287
char peeraccount[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:311
long int duration
Definition: cdr.h:301
long int amaflags
Definition: cdr.h:307
char src[AST_MAX_EXTENSION]
Definition: cdr.h:281
char dst[AST_MAX_EXTENSION]
Definition: cdr.h:283
char clid[AST_MAX_EXTENSION]
Definition: cdr.h:279
char uniqueid[AST_MAX_UNIQUEID]
Definition: cdr.h:315
int sequence
Definition: cdr.h:321
struct timeval start
Definition: cdr.h:295
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:309
char lastapp[AST_MAX_EXTENSION]
Definition: cdr.h:291
char dcontext[AST_MAX_EXTENSION]
Definition: cdr.h:285
struct timeval end
Definition: cdr.h:299
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:115
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:105

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::sequence, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by cdr_read_callback(), 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 3433 of file cdr.c.

3434 {
3435  while (cdr) {
3436  struct ast_cdr *next = cdr->next;
3437 
3438  free_variables(&cdr->varshead);
3439  ast_free(cdr);
3440  cdr = next;
3441  }
3442 }
#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 2975 of file cdr.c.

2976 {
2977  struct cdr_beitem *match = NULL;
2978  int active_count;
2979 
2980  AST_RWLIST_WRLOCK(generic_list);
2981  AST_RWLIST_TRAVERSE(generic_list, match, list) {
2982  if (!strcasecmp(name, match->name)) {
2983  break;
2984  }
2985  }
2986 
2987  if (!match) {
2988  AST_RWLIST_UNLOCK(generic_list);
2989  return 0;
2990  }
2991 
2992  active_count = ao2_container_count(active_cdrs_master);
2993 
2994  if (!match->suspended && active_count != 0) {
2995  AST_RWLIST_UNLOCK(generic_list);
2996  ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
2997  name, active_count);
2998  return -1;
2999  }
3000 
3001  AST_RWLIST_REMOVE(generic_list, match, list);
3002  AST_RWLIST_UNLOCK(generic_list);
3003 
3004  ast_verb(2, "Unregistered '%s' CDR backend\n", name);
3005  ast_free(match);
3006 
3007  return 0;
3008 }
#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:381
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:2312
#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 2848 of file cdr.c.

2849 {
2850  struct ast_cdr_config *general;
2851  struct module_config *mod_cfg;
2852 
2853  mod_cfg = ao2_global_obj_ref(module_configs);
2854  if (!mod_cfg) {
2855  return NULL;
2856  }
2857  general = ao2_bump(mod_cfg->general);
2858  ao2_cleanup(mod_cfg);
2859  return general;
2860 }
#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:265
struct ast_cdr_config * general
Definition: cdr.c:239

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

3347 {
3348  struct cdr_object *cdr;
3349  struct cdr_object *cdr_obj;
3350 
3351  if (ast_strlen_zero(name)) {
3352  return 1;
3353  }
3354 
3355  cdr = cdr_object_get_by_name(channel_name);
3356  if (!cdr) {
3357  ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3358  return 1;
3359  }
3360 
3361  ao2_lock(cdr);
3362 
3363  cdr_obj = cdr->last;
3364  if (cdr_object_format_property(cdr_obj, name, value, length)) {
3365  /* Property failed; attempt variable */
3366  cdr_object_format_var_internal(cdr_obj, name, value, length);
3367  }
3368 
3369  ao2_unlock(cdr);
3370 
3371  ao2_cleanup(cdr);
3372  return 0;
3373 }
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:3265
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:3248
#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(), and cdr_read_callback().

◆ ast_cdr_is_enabled()

int ast_cdr_is_enabled ( void  )

Return TRUE if CDR subsystem is enabled.

Definition at line 2883 of file cdr.c.

2884 {
2885  return is_cdr_flag_set(CDR_ENABLED);
2886 }
static int is_cdr_flag_set(unsigned int cdr_flag)
Definition: cdr.c:1140
@ 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 4314 of file cdr.c.

4315 {
4316  if (!stasis_router) {
4317  return NULL;
4318  }
4319 
4321  return stasis_router;
4322 }

References ao2_bump, NULL, and stasis_router.

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

2971 {
2972  return cdr_generic_register((struct be_list *)&mo_list, name, desc, be);
2973 }
static int cdr_generic_register(struct be_list *generic_list, const char *name, const char *desc, ast_cdrbe be)
Definition: cdr.c:2924
static const char desc[]
Definition: cdr_radius.c:84
char * be
Definition: eagi_proxy.c:73
List of registered modifiers.
Definition: cdr.c:349

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

3016 {
3017  return ast_cdr_generic_unregister((struct be_list *)&mo_list, name);
3018 }
static int ast_cdr_generic_unregister(struct be_list *generic_list, const char *name)
Definition: cdr.c:2975

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

2966 {
2967  return cdr_generic_register(&be_list, name, desc, be);
2968 }

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

3621 {
3622  struct cdr_object *cdr;
3623  struct ast_var_t *vardata;
3624  struct cdr_object *it_cdr;
3625 
3626  cdr = cdr_object_get_by_name(channel_name);
3627  if (!cdr) {
3628  return -1;
3629  }
3630 
3631  ao2_lock(cdr);
3632  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3633  /* clear variables */
3634  if (!keep_variables) {
3635  while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_a.variables, entries))) {
3636  ast_var_delete(vardata);
3637  }
3638  if (cdr->party_b.snapshot) {
3639  while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_b.variables, entries))) {
3640  ast_var_delete(vardata);
3641  }
3642  }
3643  }
3644 
3645  /* Reset to initial state */
3646  memset(&it_cdr->start, 0, sizeof(it_cdr->start));
3647  memset(&it_cdr->end, 0, sizeof(it_cdr->end));
3648  memset(&it_cdr->answer, 0, sizeof(it_cdr->answer));
3649  it_cdr->start = ast_tvnow();
3650  it_cdr->lastevent = it_cdr->start;
3652  }
3653  ao2_unlock(cdr);
3654 
3655  ao2_cleanup(cdr);
3656  return 0;
3657 }
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:1507
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2472
#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:736

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

3376 {
3377  struct cdr_object *cdr;
3378  struct cdr_object *it_cdr;
3379  struct ast_var_t *variable;
3380  const char *var;
3381  char workspace[256];
3382  int total = 0, x = 0, i;
3383 
3384  cdr = cdr_object_get_by_name(channel_name);
3385  if (!cdr) {
3387  ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3388  }
3389  return 0;
3390  }
3391 
3392  ast_str_reset(*buf);
3393 
3394  ao2_lock(cdr);
3395  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3396  if (++x > 1) {
3397  ast_str_append(buf, 0, "\n");
3398  }
3399 
3400  AST_LIST_TRAVERSE(&it_cdr->party_a.variables, variable, entries) {
3401  if (!(var = ast_var_name(variable))) {
3402  continue;
3403  }
3404 
3405  if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variable), ""), sep) < 0) {
3406  ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3407  break;
3408  }
3409 
3410  total++;
3411  }
3412 
3413  for (i = 0; cdr_readonly_vars[i]; i++) {
3414  if (cdr_object_format_property(it_cdr, cdr_readonly_vars[i], workspace, sizeof(workspace))) {
3415  /* Unhandled read-only CDR variable. */
3416  ast_assert(0);
3417  continue;
3418  }
3419 
3420  if (!ast_strlen_zero(workspace)
3421  && ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, workspace, sep) < 0) {
3422  ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3423  break;
3424  }
3425  total++;
3426  }
3427  }
3428  ao2_unlock(cdr);
3429  ao2_cleanup(cdr);
3430  return total;
3431 }
#define var
Definition: ast_expr2f.c:614
static const char *const cdr_readonly_vars[]
Definition: cdr.c:3176
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:968
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:1117
#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:674
struct ast_var_t::@239 entries
#define ast_assert(a)
Definition: utils.h:734

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

2863 {
2864  struct module_config *mod_cfg;
2865 
2866  if (!config) {
2867  return;
2868  }
2869 
2870  mod_cfg = ao2_global_obj_ref(module_configs);
2871  if (!mod_cfg) {
2872  return;
2873  }
2874 
2875  ao2_replace(mod_cfg->general, config);
2876 
2877  cdr_set_debug_mode(mod_cfg);
2879 
2880  ao2_cleanup(mod_cfg);
2881 }
#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:219
static int cdr_toggle_runtime_options(void)
Checks if CDRs are enabled and enables/disables the necessary options.
Definition: cdr.c:4508
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 3570 of file cdr.c.

3571 {
3572  struct cdr_object *cdr;
3573  struct cdr_object *it_cdr;
3574 
3575  cdr = cdr_object_get_by_name(channel_name);
3576  if (!cdr) {
3577  return -1;
3578  }
3579 
3580  ao2_lock(cdr);
3581  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3582  if (it_cdr->fn_table == &finalized_state_fn_table) {
3583  continue;
3584  }
3585  /* Note: in general, set the flags on both the CDR record as well as the
3586  * Party A. Sometimes all we have is the Party A to look at.
3587  */
3588  ast_set_flag(&it_cdr->flags, option);
3589  ast_set_flag(&it_cdr->party_a, option);
3590  }
3591  ao2_unlock(cdr);
3592 
3593  ao2_cleanup(cdr);
3594  return 0;
3595 }
#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 appcdr_callback(), 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 3499 of file cdr.c.

3500 {
3501  struct cdr_object *cdr;
3502  struct party_b_userfield_update party_b_info = {
3504  .userfield = userfield,
3505  };
3506  struct cdr_object *it_cdr;
3507 
3508  /* Handle Party A */
3509  cdr = cdr_object_get_by_name(channel_name);
3510  if (cdr) {
3511  ao2_lock(cdr);
3512  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3513  if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3514  continue;
3515  }
3516  ast_copy_string(it_cdr->party_a.userfield, userfield,
3517  sizeof(it_cdr->party_a.userfield));
3518  }
3519  ao2_unlock(cdr);
3520  }
3521 
3522  /* Handle Party B */
3525  &party_b_info);
3526 
3527  ao2_cleanup(cdr);
3528 }
#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:3477
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:384
const char * userfield
Definition: cdr.c:3473
const char * channel_name
Definition: cdr.c:3472

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(), cdr_write_callback(), handle_request_info(), and start_monitor_exec().

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

3201 {
3202  struct cdr_object *cdr;
3203  struct cdr_object *it_cdr;
3204  struct ao2_iterator *it_cdrs;
3205  char *arg = ast_strdupa(channel_name);
3206  int x;
3207 
3208  for (x = 0; cdr_readonly_vars[x]; x++) {
3209  if (!strcasecmp(name, cdr_readonly_vars[x])) {
3210  ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!\n", name);
3211  return -1;
3212  }
3213  }
3214 
3216  if (!it_cdrs) {
3217  ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3218  return -1;
3219  }
3220 
3221  for (; (cdr = ao2_iterator_next(it_cdrs)); ao2_unlock(cdr), ao2_cleanup(cdr)) {
3222  ao2_lock(cdr);
3223  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3224  struct varshead *headp = NULL;
3225 
3226  if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3227  continue;
3228  }
3229  if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->base->name)) {
3230  headp = &it_cdr->party_a.variables;
3231  } else if (it_cdr->party_b.snapshot
3232  && !strcasecmp(channel_name, it_cdr->party_b.snapshot->base->name)) {
3233  headp = &it_cdr->party_b.variables;
3234  }
3235  if (headp) {
3236  set_variable(headp, name, value);
3237  }
3238  }
3239  }
3240  ao2_iterator_destroy(it_cdrs);
3241 
3242  return 0;
3243 }
#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:3148
static void set_variable(struct varshead *headp, const char *name, const char *value)
Definition: cdr.c:1275
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 3010 of file cdr.c.

3011 {
3013 }

References ast_cdr_generic_unregister(), and name.

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

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

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

1625 {
1626  /* Base process bridge enter simply indicates that we can't handle it */
1627  return BRIDGE_ENTER_NEED_CDR;
1628 }

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

1615 {
1616  return 0;
1617 }

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

1620 {
1621  return 0;
1622 }

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

1631 {
1632  char park_info[128];
1633 
1634  ast_assert(!strcasecmp(parking_info->parkee->base->name, cdr->party_a.snapshot->base->name));
1635 
1636  /* Update Party A information regardless */
1637  cdr->fn_table->process_party_a(cdr, parking_info->parkee);
1638 
1639  /* Fake out where we're parked */
1640  ast_string_field_set(cdr, appl, "Park");
1641  snprintf(park_info, sizeof(park_info), "%s:%u", parking_info->parkinglot, parking_info->parkingspace);
1642  ast_string_field_set(cdr, data, park_info);
1643 
1644  /* Prevent any further changes to the App/Data fields for this record */
1646 
1647  return 0;
1648 }
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:453

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

1554 {
1555  ast_assert(strcasecmp(snapshot->base->name, cdr->party_a.snapshot->base->name) == 0);
1556 
1557  /* Finalize the CDR if we're in hangup logic and we're set to do so */
1560  cdr_object_finalize(cdr);
1561  return 0;
1562  }
1563 
1564  /*
1565  * Only record the context and extension if we aren't in a subroutine, or if
1566  * we are executing hangup logic.
1567  */
1568  if (!ast_test_flag(&snapshot->flags, AST_FLAG_SUBROUTINE_EXEC)
1570  if (strcmp(cdr->context, snapshot->dialplan->context)) {
1571  ast_string_field_set(cdr, context, snapshot->dialplan->context);
1572  }
1573  if (strcmp(cdr->exten, snapshot->dialplan->exten)) {
1574  ast_string_field_set(cdr, exten, snapshot->dialplan->exten);
1575  }
1576  }
1577 
1578  cdr_object_swap_snapshot(&cdr->party_a, snapshot);
1579 
1580  /* When Party A is originated to an application and the application exits, the stack
1581  * will attempt to clear the application and restore the dummy originate application
1582  * of "AppDialX". Prevent that, and any other application changes we might not want
1583  * here.
1584  */
1585  if (!ast_test_flag(&cdr->flags, AST_CDR_LOCK_APP)
1586  && !ast_strlen_zero(snapshot->dialplan->appl)
1587  && (strncasecmp(snapshot->dialplan->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
1588  if (strcmp(cdr->appl, snapshot->dialplan->appl)) {
1589  ast_string_field_set(cdr, appl, snapshot->dialplan->appl);
1590  }
1591  if (strcmp(cdr->data, snapshot->dialplan->data)) {
1592  ast_string_field_set(cdr, data, snapshot->dialplan->data);
1593  }
1594 
1595  /* Dial (app_dial) is a special case. Because pre-dial handlers, which
1596  * execute before the dial begins, will alter the application/data to
1597  * something people typically don't want to see, if we see a channel enter
1598  * into Dial here, we set the appl/data accordingly and lock it.
1599  */
1600  if (!strcmp(snapshot->dialplan->appl, "Dial")) {
1602  }
1603  }
1604 
1605  if (strcmp(cdr->linkedid, snapshot->peer->linkedid)) {
1606  ast_string_field_set(cdr, linkedid, snapshot->peer->linkedid);
1607  }
1610 
1611  return 0;
1612 }
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:1544
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:1490
@ CDR_END_BEFORE_H_EXTEN
Definition: cdr.h:224
@ AST_SOFTHANGUP_HANGUP_EXEC
Definition: channel.h:1154
@ AST_FLAG_SUBROUTINE_EXEC
Definition: channel.h:1058
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:750
const ast_string_field data
Definition: cdr.c:750
const ast_string_field context
Definition: cdr.c:750
const ast_string_field exten
Definition: cdr.c:750
const ast_string_field appl
Definition: cdr.c:750

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(), context, ast_channel_snapshot_dialplan::context, cdr_object::context, ast_channel_snapshot_dialplan::data, cdr_object::data, ast_channel_snapshot::dialplan, exten, 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_bridge_enter(), 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 2495 of file cdr.c.

2497 {
2498  struct cdr_object *new_cdr;
2499 
2500  new_cdr = cdr_object_create_and_append(cdr, &cdr->lastevent);
2501  if (!new_cdr) {
2502  return;
2503  }
2505  cdr_all_relink(new_cdr);
2507  ast_string_field_set(new_cdr, bridge, cdr->bridge);
2509  CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2510  new_cdr, new_cdr->party_a.snapshot->base->name,
2511  party_b->snapshot->base->name);
2512 }
struct cdr_object_fn_table bridge_state_fn_table
The virtual table for the Bridged state.
Definition: cdr.c:675
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:807
const ast_string_field bridge
Definition: cdr.c:750

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

2527 {
2528  struct cdr_object_snapshot *party_a;
2529  struct cdr_object *cand_cdr;
2530 
2531  ao2_lock(base_cand_cdr);
2532 
2533  for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->next) {
2534  /* Skip any records that are not in this bridge */
2535  if (strcmp(cand_cdr->bridge, cdr->bridge)) {
2536  continue;
2537  }
2538 
2539  /* If the candidate is us or someone we've taken on, pass on by */
2540  if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)
2541  || (cdr->party_b.snapshot
2542  && !strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name))) {
2543  break;
2544  }
2545 
2546  party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
2547  /* We're party A - make a new CDR, append it to us, and set the candidate as
2548  * Party B */
2549  if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
2550  bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
2551  break;
2552  }
2553 
2554  /* We're Party B. Check if we can add ourselves immediately or if we need
2555  * a new CDR for them (they already have a Party B) */
2556  if (cand_cdr->party_b.snapshot
2557  && strcasecmp(cand_cdr->party_b.snapshot->base->name, cdr->party_a.snapshot->base->name)) {
2558  bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a);
2559  } else {
2560  CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2561  cand_cdr, cand_cdr->party_a.snapshot->base->name,
2562  cdr->party_a.snapshot->base->name);
2563  cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
2564  cdr_all_relink(cand_cdr);
2565  /* It's possible that this joined at one point and was never chosen
2566  * as party A. Clear their end time, as it would be set in such a
2567  * case.
2568  */
2569  memset(&cand_cdr->end, 0, sizeof(cand_cdr->end));
2570  }
2571 
2572  break;
2573  }
2574 
2575  ao2_unlock(base_cand_cdr);
2576 }
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:1205
static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, struct cdr_object_snapshot *party_b)
Definition: cdr.c:2495
A wrapper object around a snapshot. Fields that are mutable by the CDR engine are replicated here.
Definition: cdr.c:720

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

2029 {
2030  if (strcmp(cdr->bridge, bridge->uniqueid)) {
2031  return 1;
2032  }
2033  if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)
2034  && cdr->party_b.snapshot
2035  && strcasecmp(cdr->party_b.snapshot->base->name, channel->base->name)) {
2036  return 1;
2037  }
2039 
2040  return 0;
2041 }
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

Definition at line 2015 of file cdr.c.

2016 {
2018  && !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
2019 
2020  cdr_object_swap_snapshot(&cdr->party_b, snapshot);
2021 
2022  /* If party B hangs up, finalize this CDR */
2025  }
2026 }
@ AST_FLAG_DEAD
Definition: channel.h:1045

References ast_assert, AST_FLAG_DEAD, ast_test_flag, ast_channel_snapshot::base, cdr_object_swap_snapshot(), cdr_object_transition_state(), finalized_state_fn_table, ast_channel_snapshot::flags, ast_channel_snapshot_base::name, cdr_object::party_b, and cdr_object_snapshot::snapshot.

◆ cdr_all_cmp_fn()

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

Definition at line 929 of file cdr.c.

930 {
931  struct cdr_object *left = obj;
932  struct cdr_object *right = arg;
933  const char *right_key = arg;
934  int cmp;
935 
936  switch (flags & OBJ_SEARCH_MASK) {
937  case OBJ_SEARCH_OBJECT:
938  right_key = right->party_b_name;
939  /* Fall through */
940  case OBJ_SEARCH_KEY:
941  cmp = strcasecmp(left->party_b_name, right_key);
942  break;
944  /*
945  * We could also use a partial key struct containing a length
946  * so strlen() does not get called for every comparison instead.
947  */
948  cmp = strncasecmp(left->party_b_name, right_key, strlen(right_key));
949  break;
950  default:
951  /* Sort can only work on something with a full or partial key. */
952  ast_assert(0);
953  cmp = 0;
954  break;
955  }
956  return cmp ? 0 : CMP_MATCH;
957 }
@ 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:750

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

906 {
907  const struct cdr_object *cdr;
908  const char *key;
909 
910  switch (flags & OBJ_SEARCH_MASK) {
911  case OBJ_SEARCH_KEY:
912  key = obj;
913  break;
914  case OBJ_SEARCH_OBJECT:
915  cdr = obj;
916  key = cdr->party_b_name;
917  break;
918  default:
919  ast_assert(0);
920  return 0;
921  }
922  return ast_str_case_hash(key);
923 }
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:1281

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

4493 {
4494  struct cdr_object *cdr = v_obj;
4495 
4496  if (!cdr) {
4497  return;
4498  }
4499  prnt(where, "Party A: %s; Party B: %s; Bridge %s",
4500  cdr->party_a.snapshot->base->name,
4501  cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<unknown>",
4502  cdr->bridge);
4503 }

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

965 {
967  if (cdr->party_b.snapshot) {
968  if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->base->name)) {
970  ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->base->name);
972  }
973  } else {
975  ast_string_field_set(cdr, party_b_name, "");
976  }
978 }
#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 985 of file cdr.c.

986 {
987  struct cdr_object *cur;
988  struct cdr_object *next;
989 
990  ast_assert(cdr->is_root);
991 
992  /* Hold a ref to the root CDR to ensure the list members don't go away on us. */
993  ao2_ref(cdr, +1);
995  for (cur = cdr; cur; cur = next) {
996  next = cur->next;
998  /*
999  * It is safe to still use cur after unlinking because the
1000  * root CDR holds a ref to all the CDRs in the list and we
1001  * have a ref to the root CDR.
1002  */
1004  }
1006  ao2_ref(cdr, -1);
1007 }
int is_root
Definition: cdr.c:753

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

3864 {
3865  struct cdr_batch_item *newtail;
3866  int curr;
3867  RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
3868  int submit_batch = 0;
3869 
3870  if (!cdr) {
3871  return;
3872  }
3873 
3874  /* maybe they disabled CDR stuff completely, so just drop it */
3875  if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
3876  ast_debug(1, "Dropping CDR !\n");
3877  ast_cdr_free(cdr);
3878  return;
3879  }
3880 
3881  /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
3882  if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
3883  post_cdr(cdr);
3884  ast_cdr_free(cdr);
3885  return;
3886  }
3887 
3888  /* otherwise, each CDR gets put into a batch list (at the end) */
3889  ast_debug(1, "CDR detaching from this thread\n");
3890 
3891  /* we'll need a new tail for every CDR */
3892  if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
3893  post_cdr(cdr);
3894  ast_cdr_free(cdr);
3895  return;
3896  }
3897 
3898  /* don't traverse a whole list (just keep track of the tail) */
3900  if (!batch)
3901  init_batch();
3902  if (!batch->head) {
3903  /* new batch is empty, so point the head at the new tail */
3904  batch->head = newtail;
3905  } else {
3906  /* already got a batch with something in it, so just append a new tail */
3907  batch->tail->next = newtail;
3908  }
3909  newtail->cdr = cdr;
3910  batch->tail = newtail;
3911  curr = batch->size++;
3912 
3913  /* if we have enough stuff to post, then do it */
3914  if (curr >= (mod_cfg->general->batch_settings.size - 1)) {
3915  submit_batch = 1;
3916  }
3918 
3919  /* Don't submit a batch with cdr_batch_lock held */
3920  if (submit_batch) {
3921  start_batch_mode();
3922  }
3923 }
void ast_cdr_free(struct ast_cdr *cdr)
Free a CDR record.
Definition: cdr.c:3433
static ast_mutex_t cdr_batch_lock
Lock protecting modifications to the batch queue.
Definition: cdr.c:374
static struct cdr_batch * batch
static int init_batch(void)
Definition: cdr.c:3760
static void start_batch_mode(void)
Definition: cdr.c:3847
static void post_cdr(struct ast_cdr *cdr)
Definition: cdr.c:3530
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:187
Queued CDR waiting to be batched.
Definition: cdr.c:352
struct ast_cdr * cdr
Definition: cdr.c:353
struct cdr_batch_item * next
Definition: cdr.c:354
int size
Definition: cdr.c:359
struct cdr_batch_item * head
Definition: cdr.c:360
struct cdr_batch_item * tail
Definition: cdr.c:361

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

4441 {
4442  /* Only create the thread level portions once */
4443  if (cdr_thread == AST_PTHREADT_NULL) {
4446  ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
4447  return;
4448  }
4449  }
4450 
4451  /* Start the batching process */
4452  start_batch_mode();
4453 
4454  ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %u or time %u seconds.\n",
4455  config->batch_settings.size, config->batch_settings.time);
4456 }
static pthread_t cdr_thread
Definition: cdr.c:371
static ast_cond_t cdr_pending_cond
Definition: cdr.c:378
static void * do_cdr(void *data)
Definition: cdr.c:3925
#define LOG_NOTICE
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_cond_init(cond, attr)
Definition: lock.h:199
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:587

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

4410 {
4412  stasis_router = NULL;
4413 
4415  cdr_topic = NULL;
4416 
4417  STASIS_MESSAGE_TYPE_CLEANUP(cdr_sync_message_type);
4418 
4424  sched = NULL;
4425  ast_free(batch);
4426  batch = NULL;
4427 
4428  aco_info_destroy(&cfg_info);
4429  ao2_global_obj_release(module_configs);
4430 
4431  ao2_container_unregister("cdrs_master");
4434 
4435  ao2_container_unregister("cdrs_all");
4438 }
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:4283
static struct ast_cli_entry cli_commands[]
Definition: cdr.c:4272
static void finalize_batch_mode(void)
Definition: cdr.c:4300
static struct stasis_topic * cdr_topic
The parent topic for all topics we want to aggregate for CDRs.
Definition: cdr.c:399
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:661

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

3041 {
3042  struct ast_var_t *variables;
3043 
3044  if (ast_strlen_zero(name)) {
3045  return NULL;
3046  }
3047 
3048  AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
3049  if (!strcasecmp(name, ast_var_name(variables))) {
3050  return ast_var_value(variables);
3051  }
3052  }
3053 
3054  return NULL;
3055 }

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

2925 {
2926  struct cdr_beitem *i;
2927  struct cdr_beitem *cur;
2928 
2929  if (!name) {
2930  return -1;
2931  }
2932 
2933  if (!be) {
2934  ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
2935 
2936  return -1;
2937  }
2938 
2939  i = ast_calloc(1, sizeof(*i));
2940  if (!i) {
2941  return -1;
2942  }
2943 
2944  i->be = be;
2945  ast_copy_string(i->name, name, sizeof(i->name));
2946  ast_copy_string(i->desc, desc, sizeof(i->desc));
2947 
2948  AST_RWLIST_WRLOCK(generic_list);
2949  AST_RWLIST_TRAVERSE(generic_list, cur, list) {
2950  if (!strcasecmp(name, cur->name)) {
2951  ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
2952  AST_RWLIST_UNLOCK(generic_list);
2953  ast_free(i);
2954 
2955  return -1;
2956  }
2957  }
2958 
2959  AST_RWLIST_INSERT_HEAD(generic_list, i, list);
2960  AST_RWLIST_UNLOCK(generic_list);
2961 
2962  return 0;
2963 }
#define LOG_WARNING
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
ast_cdrbe be
Definition: cdr.c:340
char desc[80]
Definition: cdr.c:339

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

3058 {
3059  if (fmt == NULL) { /* raw mode */
3060  snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
3061  } else {
3062  buf[0] = '\0';/* Ensure the buffer is initialized. */
3063  if (when.tv_sec) {
3064  struct ast_tm tm;
3065 
3066  ast_localtime(&when, &tm, NULL);
3067  ast_strftime(buf, bufsize, fmt, &tm);
3068  }
3069  }
3070 }
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
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

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

872 {
873  struct cdr_object *left = obj;
874  struct cdr_object *right = arg;
875  const char *right_key = arg;
876  int cmp;
877 
878  switch (flags & OBJ_SEARCH_MASK) {
879  case OBJ_SEARCH_OBJECT:
880  right_key = right->uniqueid;
881  /* Fall through */
882  case OBJ_SEARCH_KEY:
883  cmp = strcmp(left->uniqueid, right_key);
884  break;
886  /*
887  * We could also use a partial key struct containing a length
888  * so strlen() does not get called for every comparison instead.
889  */
890  cmp = strncmp(left->uniqueid, right_key, strlen(right_key));
891  break;
892  default:
893  /* Sort can only work on something with a full or partial key. */
894  ast_assert(0);
895  cmp = 0;
896  break;
897  }
898  return cmp ? 0 : CMP_MATCH;
899 }
const ast_string_field uniqueid
Definition: cdr.c:750

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

848 {
849  const struct cdr_object *cdr;
850  const char *key;
851 
852  switch (flags & OBJ_SEARCH_MASK) {
853  case OBJ_SEARCH_KEY:
854  key = obj;
855  break;
856  case OBJ_SEARCH_OBJECT:
857  cdr = obj;
858  key = cdr->uniqueid;
859  break;
860  default:
861  ast_assert(0);
862  return 0;
863  }
864  return ast_str_case_hash(key);
865 }

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

4468 {
4469  struct cdr_object *cdr = v_obj;
4470  struct cdr_object *it_cdr;
4471 
4472  if (!cdr) {
4473  return;
4474  }
4475  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4476  prnt(where, "Party A: %s; Party B: %s; Bridge %s\n",
4477  it_cdr->party_a.snapshot->base->name,
4478  it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<unknown>",
4479  it_cdr->bridge);
4480  }
4481 }

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_timeThis implicitly sets the state of the newly created CDR to the Single state (single_state_fn_table)

Definition at line 1053 of file cdr.c.

1054 {
1055  struct cdr_object *cdr;
1056 
1057  ast_assert(chan != NULL);
1058 
1059  cdr = ao2_alloc(sizeof(*cdr), cdr_object_dtor);
1060  if (!cdr) {
1061  return NULL;
1062  }
1063  cdr->last = cdr;
1064  if (ast_string_field_init(cdr, 64)) {
1065  ao2_cleanup(cdr);
1066  return NULL;
1067  }
1069  ast_string_field_set(cdr, name, chan->base->name);
1071  cdr->disposition = AST_CDR_NULL;
1073  cdr->lastevent = *event_time;
1074 
1075  cdr->party_a.snapshot = chan;
1076  ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
1077 
1078  CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->base->name);
1079 
1081 
1082  return cdr;
1083 }
#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:589
static int global_cdr_sequence
The global sequence counter used for CDRs.
Definition: cdr.c:365
static void cdr_object_dtor(void *obj)
cdr_object Destructor
Definition: cdr.c:1012
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:755
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
const ast_string_field uniqueid
unsigned int sequence
Definition: cdr.c:738
enum ast_cdr_disposition disposition
Definition: cdr.c:733

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

Referenced by cdr_object_create_and_append(), and handle_channel_snapshot_update_message().

◆ cdr_object_check_party_a_answer()

static void cdr_object_check_party_a_answer ( struct cdr_object cdr)
static

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

Definition at line 1507 of file cdr.c.

1508 {
1509  if (cdr->party_a.snapshot->state == AST_STATE_UP && ast_tvzero(cdr->answer)) {
1510  cdr->answer = cdr->lastevent;
1511  /* tv_usec is suseconds_t, which could be int or long */
1512  CDR_DEBUG("%p - Set answered time to %ld.%06ld\n", cdr,
1513  (long)cdr->answer.tv_sec,
1514  (long)cdr->answer.tv_usec);
1515  }
1516 }

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

1091 {
1092  struct cdr_object *new_cdr;
1093  struct cdr_object *it_cdr;
1094  struct cdr_object *cdr_last;
1095 
1096  cdr_last = cdr->last;
1097  new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot, event_time);
1098  if (!new_cdr) {
1099  return NULL;
1100  }
1101  new_cdr->disposition = AST_CDR_NULL;
1102 
1103  /* Copy over the linkedid, as it may have changed */
1104  ast_string_field_set(new_cdr, linkedid, cdr_last->linkedid);
1105  ast_string_field_set(new_cdr, appl, cdr_last->appl);
1106  ast_string_field_set(new_cdr, data, cdr_last->data);
1107  ast_string_field_set(new_cdr, context, cdr_last->context);
1108  ast_string_field_set(new_cdr, exten, cdr_last->exten);
1109 
1110  /*
1111  * If the current CDR says to disable all future ones,
1112  * keep the disable chain going
1113  */
1114  if (ast_test_flag(&cdr_last->flags, AST_CDR_FLAG_DISABLE_ALL)) {
1116  }
1117 
1118  /* Copy over other Party A information */
1119  cdr_object_snapshot_copy(&new_cdr->party_a, &cdr_last->party_a);
1120 
1121  /* Append the CDR to the end of the list */
1122  for (it_cdr = cdr; it_cdr->next; it_cdr = it_cdr->next) {
1123  it_cdr->last = new_cdr;
1124  }
1125  it_cdr->last = new_cdr;
1126  it_cdr->next = new_cdr;
1127 
1128  return new_cdr;
1129 }
static struct cdr_object * cdr_object_alloc(struct ast_channel_snapshot *chan, const struct timeval *event_time)
cdr_object constructor
Definition: cdr.c:1053
@ AST_CDR_FLAG_DISABLE_ALL
Definition: cdr.h:243

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(), context, cdr_object::context, cdr_object::data, cdr_object::disposition, exten, 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 1300 of file cdr.c.

1301 {
1302  struct ast_cdr *pub_cdr = NULL, *cdr_prev = NULL;
1303  struct cdr_object *it_cdr;
1304  struct ast_var_t *it_var, *it_copy_var;
1305  struct ast_channel_snapshot *party_a;
1306  struct ast_channel_snapshot *party_b;
1307 
1308  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
1309  struct ast_cdr *cdr_copy;
1310 
1311  /* Don't create records for CDRs where the party A was a dialed channel */
1312  if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
1313  ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
1314  it_cdr->party_a.snapshot->base->name);
1315  continue;
1316  }
1317 
1318  cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
1319  if (!cdr_copy) {
1320  ast_free(pub_cdr);
1321  return NULL;
1322  }
1323 
1324  party_a = it_cdr->party_a.snapshot;
1325  party_b = it_cdr->party_b.snapshot;
1326 
1327  /* Party A */
1328  ast_assert(party_a != NULL);
1329  ast_copy_string(cdr_copy->accountcode, party_a->base->accountcode, sizeof(cdr_copy->accountcode));
1330  cdr_copy->amaflags = party_a->amaflags;
1331  ast_copy_string(cdr_copy->channel, party_a->base->name, sizeof(cdr_copy->channel));
1332  ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller->name, party_a->caller->number, "");
1333  ast_copy_string(cdr_copy->src, party_a->caller->number, sizeof(cdr_copy->src));
1334  ast_copy_string(cdr_copy->uniqueid, party_a->base->uniqueid, sizeof(cdr_copy->uniqueid));
1335  ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
1336  ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
1337  ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
1338  ast_copy_string(cdr_copy->dcontext, it_cdr->context, sizeof(cdr_copy->dcontext));
1339 
1340  /* Party B */
1341  if (party_b) {
1342  ast_copy_string(cdr_copy->dstchannel, party_b->base->name, sizeof(cdr_copy->dstchannel));
1343  ast_copy_string(cdr_copy->peeraccount, party_b->base->accountcode, sizeof(cdr_copy->peeraccount));
1344  if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
1345  snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
1346  }
1347  }
1348  if (ast_strlen_zero(cdr_copy->userfield) && !ast_strlen_zero(it_cdr->party_a.userfield)) {
1349  ast_copy_string(cdr_copy->userfield, it_cdr->party_a.userfield, sizeof(cdr_copy->userfield));
1350  }
1351 
1352  /* Timestamps/durations */
1353  cdr_copy->start = it_cdr->start;
1354  cdr_copy->answer = it_cdr->answer;
1355  cdr_copy->end = it_cdr->end;
1356  cdr_copy->billsec = cdr_object_get_billsec(it_cdr);
1357  cdr_copy->duration = cdr_object_get_duration(it_cdr);
1358 
1359  /* Flags and IDs */
1360  ast_copy_flags(cdr_copy, &it_cdr->flags, AST_FLAGS_ALL);
1361  ast_copy_string(cdr_copy->linkedid, it_cdr->linkedid, sizeof(cdr_copy->linkedid));
1362  cdr_copy->disposition = it_cdr->disposition;
1363  cdr_copy->sequence = it_cdr->sequence;
1364 
1365  /* Variables */
1366  copy_variables(&cdr_copy->varshead, &it_cdr->party_a.variables);
1367  AST_LIST_TRAVERSE(&it_cdr->party_b.variables, it_var, entries) {
1368  int found = 0;
1369  struct ast_var_t *newvariable;
1370  AST_LIST_TRAVERSE(&cdr_copy->varshead, it_copy_var, entries) {
1371  if (!strcasecmp(ast_var_name(it_var), ast_var_name(it_copy_var))) {
1372  found = 1;
1373  break;
1374  }
1375  }
1376  if (!found && (newvariable = ast_var_assign(ast_var_name(it_var), ast_var_value(it_var)))) {
1377  AST_LIST_INSERT_TAIL(&cdr_copy->varshead, newvariable, entries);
1378  }
1379  }
1380 
1381  if (!pub_cdr) {
1382  pub_cdr = cdr_copy;
1383  cdr_prev = pub_cdr;
1384  } else {
1385  cdr_prev->next = cdr_copy;
1386  cdr_prev = cdr_copy;
1387  }
1388  }
1389 
1390  return pub_cdr;
1391 }
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1073
static long cdr_object_get_duration(struct cdr_object *cdr)
Definition: cdr.c:1240
static long cdr_object_get_billsec(struct cdr_object *cdr)
Compute the billsec for a cdr_object.
Definition: cdr.c:1248
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:1192
#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::sequence, cdr_object::sequence, cdr_object_snapshot::snapshot, snapshot_is_dialed(), ast_cdr::src, ast_cdr::start, cdr_object::start, 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 1399 of file cdr.c.

1400 {
1401  struct ast_cdr *pub_cdr;
1402 
1403  CDR_DEBUG("%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
1404  cdr->party_a.snapshot->base->name,
1405  cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<none>");
1406  pub_cdr = cdr_object_create_public_records(cdr);
1407  cdr_detach(pub_cdr);
1408 }
static void cdr_detach(struct ast_cdr *cdr)
Definition: cdr.c:3863
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:1300

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

4284 {
4285  struct cdr_object *cdr = obj;
4286  struct cdr_object *it_cdr;
4287 
4288  ao2_lock(cdr);
4289  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4291  }
4292  cdr_object_dispatch(cdr);
4293  ao2_unlock(cdr);
4294 
4295  cdr_all_unlink(cdr);
4296 
4297  return CMP_MATCH;
4298 }
static void cdr_all_unlink(struct cdr_object *cdr)
Definition: cdr.c:985
static void cdr_object_dispatch(struct cdr_object *cdr)
Dispatch a CDR.
Definition: cdr.c:1399

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

1013 {
1014  struct cdr_object *cdr = obj;
1015  struct ast_var_t *it_var;
1016 
1019  while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_a.variables, entries))) {
1020  ast_var_delete(it_var);
1021  }
1022  while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_b.variables, entries))) {
1023  ast_var_delete(it_var);
1024  }
1026 
1027  /* CDR destruction used to work by calling ao2_cleanup(next) and
1028  * allowing the chain to destroy itself neatly. Unfortunately, for
1029  * really long chains, this can result in a stack overflow. So now
1030  * when the root CDR is destroyed, it is responsible for unreffing
1031  * all CDRs in the chain
1032  */
1033  if (cdr->is_root) {
1034  struct cdr_object *curr = cdr->next;
1035  struct cdr_object *next;
1036 
1037  while (curr) {
1038  next = curr->next;
1039  ao2_cleanup(curr);
1040  curr = next;
1041  }
1042  }
1043 }
#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 1453 of file cdr.c.

1454 {
1455  if (!ast_tvzero(cdr->end)) {
1456  return;
1457  }
1458  cdr->end = cdr->lastevent;
1459 
1460  if (cdr->disposition == AST_CDR_NULL) {
1461  if (!ast_tvzero(cdr->answer)) {
1463  } else if (cdr->party_a.snapshot->hangup->cause) {
1465  } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangup->cause) {
1467  } else {
1468  cdr->disposition = AST_CDR_FAILED;
1469  }
1470  }
1471 
1472  /* tv_usec is suseconds_t, which could be int or long */
1473  ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dur %.3f bill %.3f dispo %s\n",
1474  cdr->party_a.snapshot->base->name,
1475  (long)cdr->start.tv_sec,
1476  (long)cdr->start.tv_usec,
1477  (long)cdr->answer.tv_sec,
1478  (long)cdr->answer.tv_usec,
1479  (long)cdr->end.tv_sec,
1480  (long)cdr->end.tv_usec,
1481  (double)ast_tvdiff_ms(cdr->end, cdr->start) / 1000.0,
1482  (double)ast_tvdiff_ms(cdr->end, cdr->answer) / 1000.0,
1484 }
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:1415
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(), 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 2208 of file cdr.c.

2209 {
2210  struct cdr_object *cdr = obj;
2211 
2212  if (!strcasecmp(cdr->party_b_name, arg)) {
2213 #ifdef AST_DEVMODE
2214  struct ast_channel_snapshot *party_b = data;
2215 
2216  /*
2217  * For sanity's sake we also assert the party_b snapshot
2218  * is consistent with the key.
2219  */
2221  && !strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name));
2222 #endif
2223 
2224  /* Don't transition to the finalized state - let the Party A do
2225  * that when its ready
2226  */
2227  cdr_object_finalize(cdr);
2228  }
2229  return 0;
2230 }

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

3266 {
3267  struct ast_channel_snapshot *party_a = cdr_obj->party_a.snapshot;
3268  struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
3269 
3270  if (!strcasecmp(name, "clid")) {
3271  ast_callerid_merge(value, length, party_a->caller->name, party_a->caller->number, "");
3272  } else if (!strcasecmp(name, "src")) {
3273  ast_copy_string(value, party_a->caller->number, length);
3274  } else if (!strcasecmp(name, "dst")) {
3275  ast_copy_string(value, party_a->dialplan->exten, length);
3276  } else if (!strcasecmp(name, "dcontext")) {
3277  ast_copy_string(value, party_a->dialplan->context, length);
3278  } else if (!strcasecmp(name, "channel")) {
3279  ast_copy_string(value, party_a->base->name, length);
3280  } else if (!strcasecmp(name, "dstchannel")) {
3281  if (party_b) {
3282  ast_copy_string(value, party_b->base->name, length);
3283  } else {
3284  ast_copy_string(value, "", length);
3285  }
3286  } else if (!strcasecmp(name, "lastapp")) {
3287  ast_copy_string(value, party_a->dialplan->appl, length);
3288  } else if (!strcasecmp(name, "lastdata")) {
3289  ast_copy_string(value, party_a->dialplan->data, length);
3290  } else if (!strcasecmp(name, "start")) {
3291  cdr_get_tv(cdr_obj->start, NULL, value, length);
3292  } else if (!strcasecmp(name, "answer")) {
3293  cdr_get_tv(cdr_obj->answer, NULL, value, length);
3294  } else if (!strcasecmp(name, "end")) {
3295  cdr_get_tv(cdr_obj->end, NULL, value, length);
3296  } else if (!strcasecmp(name, "duration")) {
3297  snprintf(value, length, "%ld", cdr_object_get_duration(cdr_obj));
3298  } else if (!strcasecmp(name, "billsec")) {
3299  snprintf(value, length, "%ld", cdr_object_get_billsec(cdr_obj));
3300  } else if (!strcasecmp(name, "disposition")) {
3301  snprintf(value, length, "%u", cdr_obj->disposition);
3302  } else if (!strcasecmp(name, "amaflags")) {
3303  snprintf(value, length, "%d", party_a->amaflags);
3304  } else if (!strcasecmp(name, "accountcode")) {
3305  ast_copy_string(value, party_a->base->accountcode, length);
3306  } else if (!strcasecmp(name, "peeraccount")) {
3307  if (party_b) {
3308  ast_copy_string(value, party_b->base->accountcode, length);
3309  } else {
3310  ast_copy_string(value, "", length);
3311  }
3312  } else if (!strcasecmp(name, "uniqueid")) {
3313  ast_copy_string(value, party_a->base->uniqueid, length);
3314  } else if (!strcasecmp(name, "linkedid")) {
3315  ast_copy_string(value, cdr_obj->linkedid, length);
3316  } else if (!strcasecmp(name, "userfield")) {
3317  ast_copy_string(value, cdr_obj->party_a.userfield, length);
3318  } else if (!strcasecmp(name, "sequence")) {
3319  snprintf(value, length, "%u", cdr_obj->sequence);
3320  } else {
3321  return 1;
3322  }
3323 
3324  return 0;
3325 }

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

3249 {
3250  struct ast_var_t *variable;
3251 
3252  AST_LIST_TRAVERSE(&cdr->party_a.variables, variable, entries) {
3253  if (!strcasecmp(name, ast_var_name(variable))) {
3254  ast_copy_string(value, ast_var_value(variable), length);
3255  return;
3256  }
3257  }
3258 
3259  *value = '\0';
3260 }

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

1249 {
1250  long int ms;
1251 
1252  if (ast_tvzero(cdr->answer)) {
1253  return 0;
1254  }
1255 
1256  ms = ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->answer);
1257  if (ms % 1000 >= 500
1259  ms = (ms / 1000) + 1;
1260  } else {
1261  ms = ms / 1000;
1262  }
1263 
1264  return ms;
1265 }
@ 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 3334 of file cdr.c.

3335 {
3336  char *param;
3337 
3338  if (ast_strlen_zero(name)) {
3339  return NULL;
3340  }
3341 
3342  param = ast_strdupa(name);
3344 }
static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
Definition: cdr.c:3164

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

3165 {
3166  struct cdr_object *cdr = obj;
3167  const char *name = arg;
3168 
3169  if (!strcasecmp(cdr->party_a.snapshot->base->name, name)) {
3170  return CMP_MATCH;
3171  }
3172  return 0;
3173 }

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

1241 {
1242  return (long)(ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->start) / 1000);
1243 }

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

2386 {
2387  struct cdr_object *cdr = obj;
2388  struct bridge_leave_data *leave_data = data;
2389 
2390  if (cdr->fn_table == &bridge_state_fn_table
2391  && !strcmp(cdr->bridge, leave_data->bridge->uniqueid)
2392  && !strcasecmp(cdr->party_b_name, arg)) {
2393  /*
2394  * For sanity's sake we also assert the party_b snapshot
2395  * is consistent with the key.
2396  */
2398  && !strcasecmp(cdr->party_b.snapshot->base->name, leave_data->channel->base->name));
2399 
2400  /* It is our Party B, in our bridge. Set the last event and let the handler
2401  * transition our CDR appropriately when we leave the bridge.
2402  */
2403  cdr->lastevent = *leave_data->lastevent;
2404  cdr_object_finalize(cdr);
2405  }
2406  return 0;
2407 }
const struct timeval * lastevent
Definition: cdr.c:2381
struct ast_bridge_snapshot * bridge
Definition: cdr.c:2379
struct ast_channel_snapshot * channel
Definition: cdr.c:2380

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

1206 {
1207  /* Check whether or not the party is dialed. A dialed party is never the
1208  * Party A with a party that was not dialed.
1209  */
1210  if (!snapshot_is_dialed(left->snapshot) && snapshot_is_dialed(right->snapshot)) {
1211  return left;
1212  } else if (snapshot_is_dialed(left->snapshot) && !snapshot_is_dialed(right->snapshot)) {
1213  return right;
1214  }
1215 
1216  /* Try the Party A flag */
1218  return left;
1219  } else if (!ast_test_flag(left, AST_CDR_FLAG_PARTY_A) && ast_test_flag(right, AST_CDR_FLAG_PARTY_A)) {
1220  return right;
1221  }
1222 
1223  /* Neither party is dialed and neither has the Party A flag - defer to
1224  * creation time */
1225  if (left->snapshot->base->creationtime.tv_sec < right->snapshot->base->creationtime.tv_sec) {
1226  return left;
1227  } else if (left->snapshot->base->creationtime.tv_sec > right->snapshot->base->creationtime.tv_sec) {
1228  return right;
1229  } else if (left->snapshot->base->creationtime.tv_usec > right->snapshot->base->creationtime.tv_usec) {
1230  return right;
1231  } else {
1232  /* Okay, fine, take the left one */
1233  return left;
1234  }
1235 }
@ AST_CDR_FLAG_PARTY_A
Definition: cdr.h:244

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

3149 {
3150  struct cdr_object *cdr = obj;
3151  const char *name = arg;
3152 
3153  if (!strcasecmp(cdr->party_a.snapshot->base->name, name) ||
3154  (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->base->name, name))) {
3155  return CMP_MATCH;
3156  }
3157  return 0;
3158 }

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

1416 {
1417  /* Change the disposition based on the hang up cause */
1418  switch (hangupcause) {
1419  case AST_CAUSE_BUSY:
1420  cdr->disposition = AST_CDR_BUSY;
1421  break;
1422  case AST_CAUSE_CONGESTION:
1424  cdr->disposition = AST_CDR_FAILED;
1425  } else {
1427  }
1428  break;
1431  cdr->disposition = AST_CDR_FAILED;
1432  break;
1434  case AST_CAUSE_NO_ANSWER:
1436  break;
1437  default:
1438  break;
1439  }
1440 }
#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 807 of file cdr.c.

808 {
809  ao2_t_replace(dst->snapshot, src->snapshot, "CDR snapshot copy");
810  strcpy(dst->userfield, src->userfield);
811  dst->flags = src->flags;
812  copy_variables(&dst->variables, &src->variables);
813 }
#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(), 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 1544 of file cdr.c.

1546 {
1547  cdr_object_update_cid(old_snapshot, new_snapshot);
1548  ao2_t_replace(old_snapshot->snapshot, new_snapshot, "Swap CDR shapshot");
1549 }
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:1519

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_bridge_enter(), 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 821 of file cdr.c.

822 {
823  CDR_DEBUG("%p - Transitioning CDR for %s from state %s to %s\n",
824  cdr, cdr->party_a.snapshot->base->name,
825  cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
826  cdr->fn_table = fn_table;
827 
828  if (cdr->fn_table->init_function && do_init) {
829  cdr->fn_table->init_function(cdr);
830  }
831 }
const char * name
Name of the subclass.
Definition: cdr.c:434
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:443

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_bridge_enter().

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

1520 {
1521  if (!old_snapshot->snapshot) {
1522  set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1523  set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1524  set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1525  return;
1526  }
1527  if (strcmp(old_snapshot->snapshot->caller->dnid, new_snapshot->caller->dnid)) {
1528  set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1529  }
1530  if (strcmp(old_snapshot->snapshot->caller->subaddr, new_snapshot->caller->subaddr)) {
1531  set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1532  }
1533  if (strcmp(old_snapshot->snapshot->caller->dialed_subaddr, new_snapshot->caller->dialed_subaddr)) {
1534  set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1535  }
1536 }
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 2232 of file cdr.c.

2233 {
2234  struct cdr_object *cdr = obj;
2235 
2236  if (cdr->fn_table->process_party_b
2237  && !strcasecmp(cdr->party_b_name, arg)) {
2238  struct ast_channel_snapshot *party_b = data;
2239 
2240  /*
2241  * For sanity's sake we also check the party_b snapshot
2242  * for consistency with the key. The callback needs and
2243  * asserts the snapshot to be this way.
2244  */
2245  if (!cdr->party_b.snapshot
2246  || strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name)) {
2248  "CDR for Party A %s(%s) has inconsistent Party B %s name. Message can be ignored but this shouldn't happen.\n",
2249  cdr->linkedid,
2250  cdr->party_a.snapshot->base->name,
2251  cdr->party_b_name);
2252  return 0;
2253  }
2254 
2255  cdr->fn_table->process_party_b(cdr, party_b);
2256  }
2257  return 0;
2258 }
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:462

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

3478 {
3479  struct cdr_object *cdr = obj;
3480 
3481  if ((cdr->fn_table != &finalized_state_fn_table || !cdr->next)
3482  && !strcasecmp(cdr->party_b_name, arg)) {
3483  struct party_b_userfield_update *info = data;
3484 
3485  /*
3486  * For sanity's sake we also assert the party_b snapshot
3487  * is consistent with the key.
3488  */
3490  && !strcasecmp(cdr->party_b.snapshot->base->name, info->channel_name));
3491 
3492  ast_copy_string(cdr->party_b.userfield, info->userfield,
3493  sizeof(cdr->party_b.userfield));
3494  }
3495 
3496  return 0;
3497 }
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 3788 of file cdr.c.

3789 {
3790  struct module_config *mod_cfg;
3791  struct cdr_batch_item *oldbatchitems = NULL;
3792  pthread_t batch_post_thread = AST_PTHREADT_NULL;
3793 
3794  /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
3795  if (!batch || !batch->head) {
3796  return;
3797  }
3798 
3799  /* move the old CDRs aside, and prepare a new CDR batch */
3801  oldbatchitems = batch->head;
3802  reset_batch();
3804 
3805  mod_cfg = ao2_global_obj_ref(module_configs);
3806 
3807  /* if configured, spawn a new thread to post these CDRs,
3808  also try to save as much as possible if we are shutting down safely */
3809  if (!mod_cfg
3811  || do_shutdown) {
3812  ast_debug(1, "CDR single-threaded batch processing begins now\n");
3813  do_batch_backend_process(oldbatchitems);
3814  } else {
3815  if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
3816  ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
3817  do_batch_backend_process(oldbatchitems);
3818  } else {
3819  ast_debug(1, "CDR multi-threaded batch processing begins now\n");
3820  }
3821  }
3822 
3823  ao2_cleanup(mod_cfg);
3824 }
static void reset_batch(void)
Definition: cdr.c:3752
static void * do_batch_backend_process(void *data)
Definition: cdr.c:3771
@ BATCH_MODE_SCHEDULER_ONLY
Definition: cdr.h:232
struct ast_flags settings
Definition: cdr.h:270
struct ast_cdr_config::batch_settings batch_settings
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:592

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

4509 {
4510  struct module_config *mod_cfg;
4511 
4512  mod_cfg = ao2_global_obj_ref(module_configs);
4513  if (mod_cfg
4514  && ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4515  if (create_subscriptions()) {
4517  ast_log(AST_LOG_ERROR, "Failed to create Stasis subscriptions\n");
4518  ao2_cleanup(mod_cfg);
4519  return -1;
4520  }
4521  if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4522  cdr_enable_batch_mode(mod_cfg->general);
4523  } else {
4524  ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
4525  }
4526  } else {
4528  ast_log(LOG_NOTICE, "CDR logging disabled.\n");
4529  }
4530  ao2_cleanup(mod_cfg);
4531 
4532  return mod_cfg ? 0 : -1;
4533 }
static int create_subscriptions(void)
Create the Stasis subcriptions for CDRs.
Definition: cdr.c:4337
static void cdr_enable_batch_mode(struct ast_cdr_config *config)
Definition: cdr.c:4440
static void destroy_subscriptions(void)
Destroy the active Stasis subscriptions.
Definition: cdr.c:4327
struct ast_flags settings
Definition: cdr.h:266

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(), and load_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 2261 of file cdr.c.

2263 {
2264  /* If we're dead, we don't need a new CDR */
2265  if (!new_snapshot
2268  return 0;
2269  }
2270 
2271  /* Auto-fall through will increment the priority but have no application */
2272  if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
2273  return 0;
2274  }
2275 
2276  if (old_snapshot && !snapshot_cep_changed(old_snapshot, new_snapshot)) {
2277  return 0;
2278  }
2279 
2280  return 1;
2281 }
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:1161

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

3993 {
3994  int wordlen = strlen(a->word);
3995  struct ao2_iterator it_cdrs;
3996  struct cdr_object *cdr;
3997 
3998  it_cdrs = ao2_iterator_init(active_cdrs_master, 0);
3999  while ((cdr = ao2_iterator_next(&it_cdrs))) {
4000  if (!strncasecmp(a->word, cdr->party_a.snapshot->base->name, wordlen)) {
4002  ao2_ref(cdr, -1);
4003  break;
4004  }
4005  }
4006  ao2_ref(cdr, -1);
4007  }
4008  ao2_iterator_destroy(&it_cdrs);
4009 
4010  return NULL;
4011 }
#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:2760
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 4077 of file cdr.c.

4078 {
4079  struct cdr_object *it_cdr;
4080  char clid[64];
4081  char start_time_buffer[64];
4082  char answer_time_buffer[64];
4083  char end_time_buffer[64];
4084  const char *channel_name = a->argv[3];
4085  struct cdr_object *cdr;
4086 
4087 #define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4088 #define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4089 
4090  cdr = cdr_object_get_by_name(channel_name);
4091  if (!cdr) {
4092  ast_cli(a->fd, "Unknown channel: %s\n", channel_name);
4093  return;
4094  }
4095 
4096  ast_cli(a->fd, "\n");
4097  ast_cli(a->fd, "Call Detail Record (CDR) Information for %s\n", channel_name);
4098  ast_cli(a->fd, "--------------------------------------------------\n");
4099  ast_cli(a->fd, TITLE_STRING, "AccountCode", "CallerID", "Dst. Channel", "LastApp", "Data", "Start", "Answer", "End", "Billsec", "Duration");
4100 
4101  ao2_lock(cdr);
4102  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4103  struct timeval end;
4104 
4105  if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4106  continue;
4107  }
4108  ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller->name, it_cdr->party_a.snapshot->caller->number, "");
4109  if (ast_tvzero(it_cdr->end)) {
4110  end = ast_tvnow();
4111  } else {
4112  end = it_cdr->end;
4113  }
4114  cdr_get_tv(it_cdr->start, "%T", start_time_buffer, sizeof(start_time_buffer));
4115  cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4116  cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
4117  ast_cli(a->fd, FORMAT_STRING,
4118  it_cdr->party_a.snapshot->base->accountcode,
4119  clid,
4120  it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4121  it_cdr->appl,
4122  it_cdr->data,
4123  start_time_buffer,
4124  answer_time_buffer,
4125  end_time_buffer,
4126  (long)ast_tvdiff_ms(end, it_cdr->answer) / 1000,
4127  (long)ast_tvdiff_ms(end, it_cdr->start) / 1000);
4128  }
4129  ao2_unlock(cdr);
4130 
4131  ao2_cleanup(cdr);
4132 
4133 #undef FORMAT_STRING
4134 #undef TITLE_STRING
4135 }
#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 4013 of file cdr.c.

4014 {
4015  struct ao2_iterator it_cdrs;
4016  struct cdr_object *cdr;
4017  char start_time_buffer[64];
4018  char answer_time_buffer[64];
4019  char end_time_buffer[64];
4020 
4021 #define TITLE_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4022 #define FORMAT_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4023 
4024  ast_cli(a->fd, "\n");
4025  ast_cli(a->fd, "Channels with Call Detail Record (CDR) Information\n");
4026  ast_cli(a->fd, "--------------------------------------------------\n");
4027  ast_cli(a->fd, TITLE_STRING, "Channel", "Dst. Channel", "LastApp", "Start", "Answer", "End", "Billsec", "Duration");
4028 
4029  it_cdrs = ao2_iterator_init(active_cdrs_master, 0);
4030  for (; (cdr = ao2_iterator_next(&it_cdrs)); ao2_cleanup(cdr)) {
4031  struct cdr_object *it_cdr;
4032  struct timeval start_time = { 0, };
4033  struct timeval answer_time = { 0, };
4034  struct timeval end_time = { 0, };
4035 
4036  SCOPED_AO2LOCK(lock, cdr);
4037 
4038  /* Calculate the start, end, answer, billsec, and duration over the
4039  * life of all of the CDR entries
4040  */
4041  for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4042  if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4043  continue;
4044  }
4045  if (ast_tvzero(start_time)) {
4046  start_time = it_cdr->start;
4047  }
4048  if (!ast_tvzero(it_cdr->answer) && ast_tvzero(answer_time)) {
4049  answer_time = it_cdr->answer;
4050  }
4051  }
4052 
4053  /* If there was no start time, then all CDRs were for a dialed channel; skip */
4054  if (ast_tvzero(start_time)) {
4055  continue;
4056  }
4057  it_cdr = cdr->last;
4058 
4059  end_time = ast_tvzero(it_cdr->end) ? ast_tvnow() : it_cdr->end;
4060  cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
4061  cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4062  cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
4063  ast_cli(a->fd, FORMAT_STRING, it_cdr->party_a.snapshot->base->name,
4064  it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4065  it_cdr->appl,
4066  start_time_buffer,
4067  answer_time_buffer,
4068  end_time_buffer,
4069  ast_tvzero(answer_time) ? 0 : (long)ast_tvdiff_ms(end_time, answer_time) / 1000,
4070  (long)ast_tvdiff_ms(end_time, start_time) / 1000);
4071  }
4072  ao2_iterator_destroy(&it_cdrs);
4073 #undef FORMAT_STRING
4074 #undef TITLE_STRING
4075 }

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

763 {
764  struct ast_var_t *variables;
765  struct ast_var_t *newvariable;
766  const char *var;
767  const char *val;
768  int x = 0;
769 
770  AST_LIST_TRAVERSE(from_list, variables, entries) {
771  var = ast_var_name(variables);
772  if (ast_strlen_zero(var)) {
773  continue;
774  }
775  val = ast_var_value(variables);
776  if (ast_strlen_zero(val)) {
777  continue;
778  }
779  newvariable = ast_var_assign(var, val);
780  if (newvariable) {
781  AST_LIST_INSERT_HEAD(to_list, newvariable, entries);
782  ++x;
783  }
784  }
785 
786  return x;
787 }
#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 4337 of file cdr.c.

4338 {
4339  if (!cdr_topic) {
4340  return -1;
4341  }
4342 
4344  return 0;
4345  }
4346 
4348  if (!channel_subscription) {
4349  return -1;
4350  }
4352  if (!bridge_subscription) {
4353  return -1;
4354  }
4356  if (!parking_subscription) {
4357  return -1;
4358  }
4359 
4360  return 0;
4361 }
static struct stasis_forward * bridge_subscription
Our subscription for bridges.
Definition: cdr.c:390
static struct stasis_forward * channel_subscription
Our subscription for channels.
Definition: cdr.c:393
static struct stasis_forward * parking_subscription
Our subscription for parking.
Definition: cdr.c:396
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct stasis_topic * ast_parking_topic(void)
accessor for the parking stasis topic
Definition: parking.c:67
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:1580
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 4327 of file cdr.c.

4328 {
4332 }
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1550

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

1894 {
1895  int success = 0;
1896 
1897  ast_string_field_set(cdr, bridge, bridge->uniqueid);
1898 
1899  /* Get parties in the bridge */
1900  if (ao2_container_count(bridge->channels) == 1) {
1901  /* No one in the bridge yet but us! */
1903  return BRIDGE_ENTER_ONLY_PARTY;
1904  }
1905 
1906  /* If we don't have a Party B (originated channel), skip it */
1907  if (cdr->party_b.snapshot) {
1908  struct ao2_iterator it_cdrs;
1909  char *channel_id;
1910 
1911  for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
1912  !success && (channel_id = ao2_iterator_next(&it_cdrs));
1913  ao2_ref(channel_id, -1)) {
1914  struct cdr_object *cand_cdr_master;
1915  struct cdr_object *cand_cdr;
1916 
1917  cand_cdr_master = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
1918  if (!cand_cdr_master) {
1919  continue;
1920  }
1921 
1922  ao2_lock(cand_cdr_master);
1923  for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
1924  /* Skip any records that are not in a bridge or in this bridge.
1925  * I'm not sure how that would happen, but it pays to be careful. */
1926  if (cand_cdr->fn_table != &bridge_state_fn_table
1927  || strcmp(cdr->bridge, cand_cdr->bridge)) {
1928  continue;
1929  }
1930 
1931  /* Skip any records that aren't our Party B */
1932  if (strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
1933  continue;
1934  }
1935  cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
1936  /* If they have a Party B, they joined up with someone else as their
1937  * Party A. Don't finalize them as they're active. Otherwise, we
1938  * have stolen them so they need to be finalized.
1939  */
1940  if (!cand_cdr->party_b.snapshot) {
1941  cdr_object_finalize(cand_cdr);
1942  }
1943  success = 1;
1944  break;
1945  }
1946  ao2_unlock(cand_cdr_master);
1947  ao2_cleanup(cand_cdr_master);
1948  }
1949  ao2_iterator_destroy(&it_cdrs);
1950  }
1951 
1952  /* We always transition state, even if we didn't get a peer */
1954 
1955  /* Success implies that we have a Party B */
1956  if (success) {
1958  }
1959  return BRIDGE_ENTER_NO_PARTY_B;
1960 }
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_container * channels
Definition: bridge.h:331

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

1830 {
1831  /* Don't process a begin dial here. A party A already in the dial state will
1832  * who receives a dial begin for something else will be handled by the
1833  * message router callback and will add a new CDR for the party A */
1834  return 1;
1835 }

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

1862 {
1863  struct ast_channel_snapshot *party_a;
1864 
1865  if (caller) {
1866  party_a = caller;
1867  } else {
1868  party_a = peer;
1869  }
1870  ast_assert(!strcasecmp(cdr->party_a.snapshot->base->name, party_a->base->name));
1871  cdr_object_swap_snapshot(&cdr->party_a, party_a);
1872 
1873  if (cdr->party_b.snapshot) {
1874  if (strcasecmp(cdr->party_b.snapshot->base->name, peer->base->name)) {
1875  /* Not the status for this CDR - defer back to the message router */
1876  return 1;
1877  }
1879  }
1880 
1881  /* Set the disposition based on the dial string. */
1882  cdr->disposition = dial_status_to_disposition(dial_status);
1883  if (cdr->disposition == AST_CDR_ANSWERED) {
1884  /* Switch to dial pending to wait and see what the caller does */
1886  } else {
1888  }
1889 
1890  return 0;
1891 }
static enum ast_cdr_disposition dial_status_to_disposition(const char *dial_status)
Definition: cdr.c:1841
struct cdr_object_fn_table dialed_pending_state_fn_table
The virtual table for the Dialed Pending state.
Definition: cdr.c:653

◆ dial_state_process_party_b()

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

Definition at line 1815 of file cdr.c.

1816 {
1817  ast_assert(snapshot != NULL);
1819  && !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
1820 
1821  cdr_object_swap_snapshot(&cdr->party_b, snapshot);
1822 
1823  /* If party B hangs up, finalize this CDR */
1826  }
1827 }

References ast_assert, AST_FLAG_DEAD, ast_test_flag, ast_channel_snapshot::base, cdr_object_swap_snapshot(), cdr_object_transition_state(), finalized_state_fn_table, ast_channel_snapshot::flags, ast_channel_snapshot_base::name, NULL, cdr_object::party_b, and cdr_object_snapshot::snapshot.

◆ dial_status_end()

static int dial_status_end ( const char *  dialstatus)
static

Definition at line 2102 of file cdr.c.

2103 {
2104  return (strcmp(dialstatus, "RINGING") &&
2105  strcmp(dialstatus, "PROCEEDING") &&
2106  strcmp(dialstatus, "PROGRESS"));
2107&#