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/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/data.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 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  module_config
 The configuration settings for this module. More...
struct  party_b_userfield_update

Defines

#define CDR_DEBUG(mod_cfg, fmt,...)
#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_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   "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
#define FORMAT_STRING   "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
#define MAX_BATCH_SIZE   1000
#define MAX_BATCH_TIME   86400
#define NUM_CDR_BUCKETS   769
#define TITLE_STRING   "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
#define TITLE_STRING   "%-25.25s %-25.25s %-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 __fini_be_list (void)
static void __init_be_list (void)
static AO2_GLOBAL_OBJ_STATIC (module_configs)
 The container for the module configuration.
struct ast_cdrast_cdr_alloc (void)
 Allocate a CDR record.
int ast_cdr_backend_suspend (const char *name)
 Suspend a CDR backend temporarily.
int ast_cdr_backend_unsuspend (const char *name)
 Unsuspend a CDR backend.
int ast_cdr_clear_property (const char *channel_name, enum ast_cdr_options option)
 Clear a property on a CDR for a channel.
const char * ast_cdr_disp2str (int disposition)
 Disposition to a string.
struct ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a public CDR.
int ast_cdr_engine_init (void)
 Load the configuration file cdr.conf and possibly start the CDR scheduling thread.
int ast_cdr_engine_reload (void)
 Reload the configuration file cdr.conf and start/stop CDR scheduling thread.
void ast_cdr_engine_term (void)
int ast_cdr_fork (const char *channel_name, struct ast_flags *options)
 Fork a CDR.
void ast_cdr_format_var (struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw)
 Format a CDR variable from an already posted CDR.
void ast_cdr_free (struct ast_cdr *cdr)
 Free a CDR record.
struct ast_cdr_configast_cdr_get_config (void)
 Obtain the current CDR configuration.
int ast_cdr_getvar (const char *channel_name, const char *name, char *value, size_t length)
 Retrieve a CDR variable from a channel's current CDR.
int ast_cdr_is_enabled (void)
 Return TRUE if CDR subsystem is enabled.
struct stasis_message_routerast_cdr_message_router (void)
 Return the message router for the CDR engine.
int ast_cdr_register (const char *name, const char *desc, ast_cdrbe be)
 Register a CDR handling engine.
int ast_cdr_reset (const char *channel_name, int keep_variables)
 Reset the detail record.
int ast_cdr_serialize_variables (const char *channel_name, struct ast_str **buf, char delim, char sep)
 Serializes all the data and variables for a current CDR record.
void ast_cdr_set_config (struct ast_cdr_config *config)
 Set the current CDR configuration.
int ast_cdr_set_property (const char *channel_name, enum ast_cdr_options option)
 Set a property on a CDR for a channel.
void ast_cdr_setuserfield (const char *channel_name, const char *userfield)
 Set CDR user field for channel (stored in CDR).
int ast_cdr_setvar (const char *channel_name, const char *name, const char *value)
 Set a variable on a CDR.
int ast_cdr_unregister (const char *name)
 Unregister a CDR handling engine.
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 int bridge_candidate_process (struct cdr_object *cdr, struct cdr_object *base_cand_cdr)
 Process a single bridge_candidate.
static int bridge_state_process_bridge_leave (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
static void bridge_state_process_party_b (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
static void cdr_container_print_fn (void *v_obj, void *where, ao2_prnt_fn *prnt)
static void cdr_detach (struct ast_cdr *cdr)
static void cdr_enable_batch_mode (struct ast_cdr_config *config)
static void cdr_engine_cleanup (void)
static void cdr_engine_shutdown (void)
static const char * cdr_format_var_internal (struct ast_cdr *cdr, const char *name)
static void cdr_get_tv (struct timeval when, const char *fmt, char *buf, int bufsize)
static struct cdr_objectcdr_object_alloc (struct ast_channel_snapshot *chan)
 cdr_object constructor
static int cdr_object_channel_cmp_fn (void *obj, void *arg, int flags)
static int cdr_object_channel_hash_fn (const void *obj, const int flags)
static void cdr_object_check_party_a_answer (struct cdr_object *cdr)
 Check to see if a CDR needs to be answered based on its Party A. Note that this is safe to call as much as you want - we won't answer twice.
static void cdr_object_check_party_a_hangup (struct cdr_object *cdr)
 Check to see if a CDR needs to move to the finalized state because its Party A hungup.
static struct cdr_objectcdr_object_create_and_append (struct cdr_object *cdr)
 Create a new cdr_object and append it to an existing chain.
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.
static void cdr_object_dispatch (struct cdr_object *cdr)
 Dispatch a CDR.
static int cdr_object_dispatch_all_cb (void *obj, void *arg, int flags)
 This dispatches *all* cdr_objects. It should only be used during shutdown, so that we get billing records for everything that we can.
static void cdr_object_dtor (void *obj)
 cdr_object Destructor
static void cdr_object_finalize (struct cdr_object *cdr)
 Finalize a CDR.
static int cdr_object_finalize_party_b (void *obj, void *arg, int flags)
static int cdr_object_format_property (struct cdr_object *cdr_obj, const char *name, char *value, size_t length)
 Format one of the standard properties on a cdr_object.
static void cdr_object_format_var_internal (struct cdr_object *cdr, const char *name, char *value, size_t length)
 Format a variable on a cdr_object.
static long cdr_object_get_billsec (struct cdr_object *cdr)
 Compute the billsec for a cdr_object.
static struct cdr_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, int flags)
 Callback used to notify CDRs of a Party B leaving the bridge.
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.
static int cdr_object_select_all_by_name_cb (void *obj, void *arg, int flags)
static void cdr_object_set_disposition (struct cdr_object *cdr, int hangupcause)
 Set the disposition on a cdr_object based on a hangupcause code.
static void cdr_object_snapshot_copy (struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src)
 Copy a snapshot and its details.
static void cdr_object_swap_snapshot (struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 Swap an old cdr_object_snapshot's ast_channel_snapshot for a new ast_channel_snapshot.
static void cdr_object_transition_state (struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
 Transition a cdr_object to a new state.
static void cdr_object_update_cid (struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
static int cdr_object_update_party_b (void *obj, void *arg, int flags)
static int cdr_object_update_party_b_userfield_cb (void *obj, void *arg, int flags)
 Callback used to update the userfield on Party B on all CDRs.
static void cdr_submit_batch (int shutdown)
static int cdr_toggle_runtime_options (void)
 Checks if CDRs are enabled and enables/disables the necessary options.
static int check_new_cdr_needed (struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 Determine if we need to add a new CDR based on snapshots.
static char * cli_complete_show (struct ast_cli_args *a)
 Complete user input for 'cdr show'.
static void cli_show_channel (struct ast_cli_args *a)
static void cli_show_channels (struct ast_cli_args *a)
 CONFIG_INFO_CORE ("cdr", cfg_info, module_configs, module_config_alloc,.files=ACO_FILES(&module_file_conf),)
static int copy_variables (struct varshead *to_list, struct varshead *from_list)
 Copy variables from one list to another.
static int create_subscriptions (void)
 Create the Stasis subcriptions for CDRs.
static void destroy_subscriptions (void)
 Destroy the active Stasis subscriptions.
static enum
process_bridge_enter_results 
dial_state_process_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
static int dial_state_process_dial_begin (struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
static int dial_state_process_dial_end (struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
static void dial_state_process_party_b (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
static enum ast_cdr_disposition dial_status_to_disposition (const char *dial_status)
static enum
process_bridge_enter_results 
dialed_pending_state_process_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
static int dialed_pending_state_process_dial_begin (struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
static int dialed_pending_state_process_parking_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
static int dialed_pending_state_process_party_a (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
static void * do_batch_backend_process (void *data)
static void * do_cdr (void *data)
static int filter_bridge_messages (struct ast_bridge_snapshot *bridge)
 Filter bridge messages based on bridge technology.
static int filter_channel_cache_message (struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
static int filter_channel_snapshot (struct ast_channel_snapshot *snapshot)
static void finalize_batch_mode (void)
static void finalized_state_init_function (struct cdr_object *cdr)
static int finalized_state_process_party_a (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
static void free_variables (struct varshead *headp)
 Delete all variables from a variable list.
static void handle_bridge_enter_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
static void handle_bridge_leave_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for when a channel leaves a bridge.
static void handle_bridge_pairings (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge)
 Handle creating bridge pairings for the cdr_object that just entered a bridge.
static void handle_cdr_sync_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for a synchronization message.
static void handle_channel_cache_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for Stasis-Core channel cache update messages.
static char * handle_cli_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_submit (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void handle_dial_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for Stasis-Core dial messages.
static void handle_parked_call_message (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Handler for when a channel is parked.
static void handle_parking_bridge_enter_message (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 Handle entering into a parking bridge.
static void handle_standard_bridge_enter_message (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 Handle a bridge enter message for a 'normal' bridge.
static int init_batch (void)
static void * module_config_alloc (void)
 Create a new module config object.
static void module_config_destructor (void *obj)
 Dispose of a module config object.
static 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 void reset_batch (void)
static void set_variable (struct varshead *headp, const char *name, const char *value)
static int single_state_bridge_enter_comparison (struct cdr_object *cdr, struct cdr_object *cand_cdr)
 Handle a comparison between our cdr_object and a cdr_object already in the bridge while in the Single state. The goal of this is to find a Party B for our CDR.
static void single_state_init_function (struct cdr_object *cdr)
static enum
process_bridge_enter_results 
single_state_process_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
static int single_state_process_dial_begin (struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
static int single_state_process_parking_bridge_enter (struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
static void single_state_process_party_b (struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
static int snapshot_cep_changed (struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 Return whether or not a channel has changed its state in the dialplan, subject to endbeforehexten logic.
static int snapshot_is_dialed (struct ast_channel_snapshot *snapshot)
 Return whether or not a ast_channel_snapshot is for a channel that was created as the result of a dial operation.
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (cdr_sync_message_type)
 A message type used to synchronize with the CDR topic.
static int submit_scheduled_batch (const void *data)
static void submit_unscheduled_batch (void)

Variables

static struct ao2_containeractive_cdrs_by_channel
 A container of the active CDRs indexed by Party A channel id.
static struct cdr_batchbatch
 The actual batch queue.
struct cdr_object_fn_table bridge_state_fn_table
 The virtual table for the Bridged state.
static struct stasis_forwardbridge_subscription
 Our subscription for bridges.
static ast_mutex_t cdr_batch_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
 Lock protecting modifications to the batch queue.
static ast_cond_t cdr_pending_cond
static ast_mutex_t cdr_pending_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
 These are used to wake up the CDR thread when there's work to do.
static const char *const cdr_readonly_vars []
static int cdr_sched = -1
static ast_mutex_t cdr_sched_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
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.
static struct stasis_forwardchannel_subscription
 Our subscription for channels.
static struct ast_cli_entry cli_commands []
struct cdr_object_fn_table dial_state_fn_table
 The virtual table for the Dial state.
struct cdr_object_fn_table dialed_pending_state_fn_table
 The virtual table for the Dialed Pending state.
struct cdr_object_fn_table finalized_state_fn_table
 The virtual table for the finalized state.
static struct aco_type general_option
 The type definition for general options.
static struct aco_typegeneral_options [] = ACO_TYPES(&general_option)
static int global_cdr_sequence = 0
 The global sequence counter used for CDRs.
static struct aco_file module_file_conf
 The file definition.
struct cdr_object_fn_table parked_state_fn_table
 The virtual table for the Parked state.
static struct stasis_forwardparking_subscription
 Our subscription for parking.
static struct ast_sched_contextsched
 Scheduler items.
struct cdr_object_fn_table single_state_fn_table
 The virtual table for the Single state.
static struct
stasis_message_router
stasis_router
 Message router for stasis messages regarding channel state.


Detailed Description

Call Detail Record API.

Author:
Mark Spencer <markster@digium.com>
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.


Define Documentation

#define CDR_DEBUG ( mod_cfg,
fmt,
...   ) 

#define DEFAULT_BATCH_SAFE_SHUTDOWN   "1"

Definition at line 210 of file cdr.c.

Referenced by process_config().

#define DEFAULT_BATCH_SCHEDULER_ONLY   "0"

Definition at line 209 of file cdr.c.

Referenced by process_config().

#define DEFAULT_BATCH_SIZE   "100"

Definition at line 205 of file cdr.c.

Referenced by process_config().

#define DEFAULT_BATCH_TIME   "300"

Definition at line 207 of file cdr.c.

Referenced by process_config().

#define DEFAULT_BATCHMODE   "0"

Definition at line 199 of file cdr.c.

Referenced by process_config().

#define DEFAULT_CONGESTION   "0"

Definition at line 201 of file cdr.c.

#define DEFAULT_ENABLED   "1"

Definition at line 198 of file cdr.c.

Referenced by process_config().

#define DEFAULT_END_BEFORE_H_EXTEN   "1"

Definition at line 202 of file cdr.c.

Referenced by process_config().

#define DEFAULT_INITIATED_SECONDS   "0"

Definition at line 203 of file cdr.c.

Referenced by process_config().

#define DEFAULT_UNANSWERED   "0"

Definition at line 200 of file cdr.c.

Referenced by process_config().

#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 FORMAT_STRING   "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"

#define MAX_BATCH_SIZE   1000

Definition at line 206 of file cdr.c.

Referenced by process_config().

#define MAX_BATCH_TIME   86400

Definition at line 208 of file cdr.c.

Referenced by process_config().

#define NUM_CDR_BUCKETS   769

Definition at line 195 of file cdr.c.

Referenced by ast_cdr_engine_init().

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

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


Enumeration Type Documentation

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

00353                                   {
00354    /*!
00355     * The CDR was the only party in the bridge.
00356     */
00357    BRIDGE_ENTER_ONLY_PARTY,
00358    /*!
00359     * The CDR was able to obtain a Party B from some other party already in the bridge
00360     */
00361    BRIDGE_ENTER_OBTAINED_PARTY_B,
00362    /*!
00363     * The CDR was not able to obtain a Party B
00364     */
00365    BRIDGE_ENTER_NO_PARTY_B,
00366    /*!
00367     * This CDR can't handle a bridge enter message and a new CDR needs to be created
00368     */
00369    BRIDGE_ENTER_NEED_CDR,
00370 };


Function Documentation

static void __fini_be_list ( void   )  [static]

Definition at line 298 of file cdr.c.

00301 {

static void __init_be_list ( void   )  [static]

Definition at line 298 of file cdr.c.

00301 {

static AO2_GLOBAL_OBJ_STATIC ( module_configs   )  [static]

The container for the module configuration.

struct ast_cdr* ast_cdr_alloc ( void   )  [read]

Allocate a CDR record.

Return values:
a malloc'd ast_cdr structure
NULL on error (malloc failure)

Definition at line 3167 of file cdr.c.

References ast_calloc.

Referenced by ast_cdr_dup().

03168 {
03169    struct ast_cdr *x;
03170 
03171    x = ast_calloc(1, sizeof(*x));
03172    return x;
03173 }

int ast_cdr_backend_suspend ( const char *  name  ) 

Suspend a CDR backend temporarily.

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

Definition at line 2635 of file cdr.c.

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

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

02636 {
02637    int success = -1;
02638    struct cdr_beitem *i = NULL;
02639 
02640    AST_RWLIST_WRLOCK(&be_list);
02641    AST_RWLIST_TRAVERSE(&be_list, i, list) {
02642       if (!strcasecmp(name, i->name)) {
02643          ast_debug(3, "Suspending CDR backend %s\n", i->name);
02644          i->suspended = 1;
02645          success = 0;
02646       }
02647    }
02648    AST_RWLIST_UNLOCK(&be_list);
02649 
02650    return success;
02651 }

int ast_cdr_backend_unsuspend ( const char *  name  ) 

Unsuspend a CDR backend.

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

Definition at line 2653 of file cdr.c.

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

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

02654 {
02655    int success = -1;
02656    struct cdr_beitem *i = NULL;
02657 
02658    AST_RWLIST_WRLOCK(&be_list);
02659    AST_RWLIST_TRAVERSE(&be_list, i, list) {
02660       if (!strcasecmp(name, i->name)) {
02661          ast_debug(3, "Unsuspending CDR backend %s\n", i->name);
02662          i->suspended = 0;
02663          success = 0;
02664       }
02665    }
02666    AST_RWLIST_UNLOCK(&be_list);
02667 
02668    return success;
02669 }

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_name The CDR's channel
option Option to clear from the CDR
Return values:
0 on success
1 on error

Definition at line 3297 of file cdr.c.

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, cdr_object::next, and RAII_VAR.

Referenced by appcdr_callback(), AST_TEST_DEFINE(), and cdr_prop_write_callback().

03298 {
03299    RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
03300    struct cdr_object *it_cdr;
03301 
03302    if (!cdr) {
03303       return -1;
03304    }
03305 
03306    ao2_lock(cdr);
03307    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
03308       if (it_cdr->fn_table == &finalized_state_fn_table) {
03309          continue;
03310       }
03311       ast_clear_flag(&it_cdr->flags, option);
03312    }
03313    ao2_unlock(cdr);
03314 
03315    return 0;
03316 }

const char* ast_cdr_disp2str ( int  disposition  ) 

Disposition to a string.

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

Definition at line 3175 of file cdr.c.

References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_CONGESTION, AST_CDR_FAILED, AST_CDR_NOANSWER, and AST_CDR_NULL.

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

03176 {
03177    switch (disposition) {
03178    case AST_CDR_NULL:
03179       return "NO ANSWER"; /* by default, for backward compatibility */
03180    case AST_CDR_NOANSWER:
03181       return "NO ANSWER";
03182    case AST_CDR_FAILED:
03183       return "FAILED";
03184    case AST_CDR_BUSY:
03185       return "BUSY";
03186    case AST_CDR_ANSWERED:
03187       return "ANSWERED";
03188    case AST_CDR_CONGESTION:
03189       return "CONGESTION";
03190    }
03191    return "UNKNOWN";
03192 }

struct ast_cdr* ast_cdr_dup ( struct ast_cdr cdr  )  [read]

Duplicate a public CDR.

Parameters:
cdr the record to duplicate
Return values:
a malloc'd ast_cdr structure,
NULL on error (malloc failure)

Definition at line 2740 of file cdr.c.

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(), syslog_log(), and write_cdr().

02741 {
02742    struct ast_cdr *newcdr;
02743 
02744    if (!cdr) {
02745       return NULL;
02746    }
02747    newcdr = ast_cdr_alloc();
02748    if (!newcdr) {
02749       return NULL;
02750    }
02751 
02752    *newcdr = *cdr;
02753    AST_LIST_HEAD_INIT_NOLOCK(&newcdr->varshead);
02754    copy_variables(&newcdr->varshead, &cdr->varshead);
02755    newcdr->next = NULL;
02756 
02757    return newcdr;
02758 }

int ast_cdr_engine_init ( void   ) 

Load the configuration file cdr.conf and possibly start the CDR scheduling thread.

Definition at line 4166 of file cdr.c.

References active_cdrs_by_channel, ao2_container_alloc, ao2_container_register(), ARRAY_LEN, ast_channel_dial_type(), ast_channel_entered_bridge_type(), ast_channel_left_bridge_type(), ast_channel_snapshot_type(), ast_cli_register_multiple(), ast_log, ast_parked_call_type(), ast_register_atexit(), ast_register_cleanup(), ast_sched_context_create(), cdr_container_print_fn(), cdr_engine_cleanup(), cdr_engine_shutdown(), cdr_object_channel_cmp_fn(), cdr_object_channel_hash_fn(), cdr_toggle_runtime_options(), cdr_topic, cli_commands, handle_bridge_enter_message(), handle_bridge_leave_message(), handle_cdr_sync_message(), handle_channel_cache_message(), handle_dial_message(), handle_parked_call_message(), LOG_ERROR, NULL, NUM_CDR_BUCKETS, process_config(), stasis_message_router_add(), stasis_message_router_add_cache_update(), stasis_message_router_create(), STASIS_MESSAGE_TYPE_INIT, stasis_router, and stasis_topic_create().

Referenced by main().

04167 {
04168    if (process_config(0)) {
04169       return -1;
04170    }
04171 
04172    cdr_topic = stasis_topic_create("cdr_engine");
04173    if (!cdr_topic) {
04174       return -1;
04175    }
04176 
04177    stasis_router = stasis_message_router_create(cdr_topic);
04178    if (!stasis_router) {
04179       return -1;
04180    }
04181 
04182    if (STASIS_MESSAGE_TYPE_INIT(cdr_sync_message_type)) {
04183       return -1;
04184    }
04185 
04186    stasis_message_router_add_cache_update(stasis_router, ast_channel_snapshot_type(), handle_channel_cache_message, NULL);
04187    stasis_message_router_add(stasis_router, ast_channel_dial_type(), handle_dial_message, NULL);
04188    stasis_message_router_add(stasis_router, ast_channel_entered_bridge_type(), handle_bridge_enter_message, NULL);
04189    stasis_message_router_add(stasis_router, ast_channel_left_bridge_type(), handle_bridge_leave_message, NULL);
04190    stasis_message_router_add(stasis_router, ast_parked_call_type(), handle_parked_call_message, NULL);
04191    stasis_message_router_add(stasis_router, cdr_sync_message_type(), handle_cdr_sync_message, NULL);
04192 
04193    active_cdrs_by_channel = ao2_container_alloc(NUM_CDR_BUCKETS,
04194       cdr_object_channel_hash_fn, cdr_object_channel_cmp_fn);
04195    if (!active_cdrs_by_channel) {
04196       return -1;
04197    }
04198    ao2_container_register("cdrs_by_channel", active_cdrs_by_channel, cdr_container_print_fn);
04199 
04200    sched = ast_sched_context_create();
04201    if (!sched) {
04202       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
04203       return -1;
04204    }
04205 
04206    ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
04207    ast_register_cleanup(cdr_engine_cleanup);
04208    ast_register_atexit(cdr_engine_shutdown);
04209 
04210    return cdr_toggle_runtime_options();
04211 }

int ast_cdr_engine_reload ( void   ) 

Reload the configuration file cdr.conf and start/stop CDR scheduling thread.

Definition at line 4246 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ast_test_flag, CDR_BATCHMODE, CDR_ENABLED, cdr_toggle_runtime_options(), finalize_batch_mode(), NULL, process_config(), and RAII_VAR.

04247 {
04248    RAII_VAR(struct module_config *, old_mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
04249    RAII_VAR(struct module_config *, mod_cfg, NULL, ao2_cleanup);
04250 
04251    if (process_config(1)) {
04252       return -1;
04253    }
04254 
04255    mod_cfg = ao2_global_obj_ref(module_configs);
04256 
04257    if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) ||
04258          !(ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE))) {
04259       /* If batch mode used to be enabled, finalize the batch */
04260       if (ast_test_flag(&old_mod_cfg->general->settings, CDR_BATCHMODE)) {
04261          finalize_batch_mode();
04262       }
04263    }
04264 
04265    return cdr_toggle_runtime_options();
04266 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 4213 of file cdr.c.

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

04214 {
04215    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
04216    RAII_VAR(void *, payload, NULL, ao2_cleanup);
04217    RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
04218 
04219    /* Since this is called explicitly during process shutdown, we might not have ever
04220     * been initialized. If so, the config object will be NULL.
04221     */
04222    if (!mod_cfg) {
04223       return;
04224    }
04225 
04226    if (cdr_sync_message_type()) {
04227       /* Make sure we have the needed items */
04228       payload = ao2_alloc(sizeof(*payload), NULL);
04229       if (!stasis_router || !payload) {
04230          return;
04231       }
04232 
04233       ast_debug(1, "CDR Engine termination request received; waiting on messages...\n");
04234 
04235       message = stasis_message_create(cdr_sync_message_type(), payload);
04236       if (message) {
04237          stasis_message_router_publish_sync(stasis_router, message);
04238       }
04239    }
04240 
04241    if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
04242       cdr_submit_batch(ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN));
04243    }
04244 }

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

Fork a CDR.

Since:
12
Parameters:
channel_name The name of the channel whose CDR should be forked
options Options to control how the fork occurs.
Return values:
0 on success
-1 on failure

Definition at line 3354 of file cdr.c.

References cdr_object::answer, ao2_cleanup, ao2_ref, cdr_object::appl, AST_CDR_FLAG_FINALIZE, AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_RESET, AST_CDR_FLAG_SET_ANSWER, AST_CDR_LOCK_APP, ast_clear_flag, ast_debug, AST_STATE_UP, ast_string_field_set, ast_test_flag, ast_tvnow(), cdr_object::bridge, cdr_object_create_and_append(), cdr_object_finalize(), cdr_object_get_by_name(), cdr_object_transition_state(), context, copy_variables(), cdr_object::data, exten, finalized_state_fn_table, cdr_object_snapshot::flags, ast_flags::flags, cdr_object::flags, cdr_object::fn_table, free_variables(), cdr_object::last, lock, cdr_object::next, 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().

03355 {
03356    RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
03357    struct cdr_object *new_cdr;
03358    struct cdr_object *it_cdr;
03359    struct cdr_object *cdr_obj;
03360 
03361    if (!cdr) {
03362       return -1;
03363    }
03364 
03365    {
03366       SCOPED_AO2LOCK(lock, cdr);
03367 
03368       cdr_obj = cdr->last;
03369       if (cdr_obj->fn_table == &finalized_state_fn_table) {
03370          /* If the last CDR in the chain is finalized, don't allow a fork -
03371           * things are already dying at this point
03372           */
03373          return -1;
03374       }
03375 
03376       /* Copy over the basic CDR information. The Party A information is
03377        * copied over automatically as part of the append
03378        */
03379       ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->name);
03380       new_cdr = cdr_object_create_and_append(cdr);
03381       if (!new_cdr) {
03382          return -1;
03383       }
03384       new_cdr->fn_table = cdr_obj->fn_table;
03385       ast_string_field_set(new_cdr, bridge, cdr->bridge);
03386       ast_string_field_set(new_cdr, appl, cdr->appl);
03387       ast_string_field_set(new_cdr, data, cdr->data);
03388       ast_string_field_set(new_cdr, context, cdr->context);
03389       ast_string_field_set(new_cdr, exten, cdr->exten);
03390       new_cdr->flags = cdr->flags;
03391       /* Explicitly clear the AST_CDR_LOCK_APP flag - we want
03392        * the application to be changed on the new CDR if the
03393        * dialplan demands it
03394        */
03395       ast_clear_flag(&new_cdr->flags, AST_CDR_LOCK_APP);
03396 
03397       /* If there's a Party B, copy it over as well */
03398       if (cdr_obj->party_b.snapshot) {
03399          new_cdr->party_b.snapshot = cdr_obj->party_b.snapshot;
03400          ao2_ref(new_cdr->party_b.snapshot, +1);
03401          strcpy(new_cdr->party_b.userfield, cdr_obj->party_b.userfield);
03402          new_cdr->party_b.flags = cdr_obj->party_b.flags;
03403          if (ast_test_flag(options, AST_CDR_FLAG_KEEP_VARS)) {
03404             copy_variables(&new_cdr->party_b.variables, &cdr_obj->party_b.variables);
03405          }
03406       }
03407       new_cdr->start = cdr_obj->start;
03408       new_cdr->answer = cdr_obj->answer;
03409 
03410       /* Modify the times based on the flags passed in */
03411       if (ast_test_flag(options, AST_CDR_FLAG_SET_ANSWER)
03412             && new_cdr->party_a.snapshot->state == AST_STATE_UP) {
03413          new_cdr->answer = ast_tvnow();
03414       }
03415       if (ast_test_flag(options, AST_CDR_FLAG_RESET)) {
03416          new_cdr->answer = ast_tvnow();
03417          new_cdr->start = ast_tvnow();
03418       }
03419 
03420       /* Create and append, by default, copies over the variables */
03421       if (!ast_test_flag(options, AST_CDR_FLAG_KEEP_VARS)) {
03422          free_variables(&new_cdr->party_a.variables);
03423       }
03424 
03425       /* Finalize any current CDRs */
03426       if (ast_test_flag(options, AST_CDR_FLAG_FINALIZE)) {
03427          for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->next) {
03428             if (it_cdr->fn_table == &finalized_state_fn_table) {
03429                continue;
03430             }
03431             /* Force finalization on the CDR. This will bypass any checks for
03432              * end before 'h' extension.
03433              */
03434             cdr_object_finalize(it_cdr);
03435             cdr_object_transition_state(it_cdr, &finalized_state_fn_table);
03436          }
03437       }
03438    }
03439 
03440    return 0;
03441 }

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:
cdr The dispatched CDR to process
name The name of the variable
ret Pointer to the formatted buffer
workspace A pointer to the buffer to use to format the variable
workspacelen The size of workspace
raw If non-zero and a date/time is extraced, provide epoch seconds. Otherwise format as a date/time stamp

Definition at line 2792 of file cdr.c.

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

Referenced by cdr_handler(), cdr_read_callback(), mysql_log(), odbc_log(), and pgsql_log().

02793 {
02794    const char *fmt = "%Y-%m-%d %T";
02795    const char *varbuf;
02796 
02797    if (!cdr) {
02798       return;
02799    }
02800 
02801    *ret = NULL;
02802 
02803    if (!strcasecmp(name, "clid")) {
02804       ast_copy_string(workspace, cdr->clid, workspacelen);
02805    } else if (!strcasecmp(name, "src")) {
02806       ast_copy_string(workspace, cdr->src, workspacelen);
02807    } else if (!strcasecmp(name, "dst")) {
02808       ast_copy_string(workspace, cdr->dst, workspacelen);
02809    } else if (!strcasecmp(name, "dcontext")) {
02810       ast_copy_string(workspace, cdr->dcontext, workspacelen);
02811    } else if (!strcasecmp(name, "channel")) {
02812       ast_copy_string(workspace, cdr->channel, workspacelen);
02813    } else if (!strcasecmp(name, "dstchannel")) {
02814       ast_copy_string(workspace, cdr->dstchannel, workspacelen);
02815    } else if (!strcasecmp(name, "lastapp")) {
02816       ast_copy_string(workspace, cdr->lastapp, workspacelen);
02817    } else if (!strcasecmp(name, "lastdata")) {
02818       ast_copy_string(workspace, cdr->lastdata, workspacelen);
02819    } else if (!strcasecmp(name, "start")) {
02820       cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
02821    } else if (!strcasecmp(name, "answer")) {
02822       cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
02823    } else if (!strcasecmp(name, "end")) {
02824       cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
02825    } else if (!strcasecmp(name, "duration")) {
02826       snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
02827    } else if (!strcasecmp(name, "billsec")) {
02828       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);
02829    } else if (!strcasecmp(name, "disposition")) {
02830       if (raw) {
02831          snprintf(workspace, workspacelen, "%ld", cdr->disposition);
02832       } else {
02833          ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
02834       }
02835    } else if (!strcasecmp(name, "amaflags")) {
02836       if (raw) {
02837          snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
02838       } else {
02839          ast_copy_string(workspace, ast_channel_amaflags2string(cdr->amaflags), workspacelen);
02840       }
02841    } else if (!strcasecmp(name, "accountcode")) {
02842       ast_copy_string(workspace, cdr->accountcode, workspacelen);
02843    } else if (!strcasecmp(name, "peeraccount")) {
02844       ast_copy_string(workspace, cdr->peeraccount, workspacelen);
02845    } else if (!strcasecmp(name, "uniqueid")) {
02846       ast_copy_string(workspace, cdr->uniqueid, workspacelen);
02847    } else if (!strcasecmp(name, "linkedid")) {
02848       ast_copy_string(workspace, cdr->linkedid, workspacelen);
02849    } else if (!strcasecmp(name, "userfield")) {
02850       ast_copy_string(workspace, cdr->userfield, workspacelen);
02851    } else if (!strcasecmp(name, "sequence")) {
02852       snprintf(workspace, workspacelen, "%d", cdr->sequence);
02853    } else if ((varbuf = cdr_format_var_internal(cdr, name))) {
02854       ast_copy_string(workspace, varbuf, workspacelen);
02855    } else {
02856       workspace[0] = '\0';
02857    }
02858 
02859    if (!ast_strlen_zero(workspace)) {
02860       *ret = workspace;
02861    }
02862 }

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

Definition at line 3156 of file cdr.c.

References ast_free, free_variables(), ast_cdr::next, cdr_beitem::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().

03157 {
03158    while (cdr) {
03159       struct ast_cdr *next = cdr->next;
03160 
03161       free_variables(&cdr->varshead);
03162       ast_free(cdr);
03163       cdr = next;
03164    }
03165 }

struct ast_cdr_config* ast_cdr_get_config ( void   )  [read]

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:
NULL on error
The current CDR configuration

Definition at line 2611 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ao2_ref, and RAII_VAR.

Referenced by test_cdr_init_cb().

02612 {
02613    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
02614    ao2_ref(mod_cfg->general, +1);
02615    return mod_cfg->general;
02616 }

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_name The name of the party A channel that the CDR is associated with
name The name of the variable to retrieve
value Buffer to hold the value
length The size of the buffer
Return values:
0 on success
non-zero on failure

Definition at line 3066 of file cdr.c.

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, and RAII_VAR.

Referenced by AST_TEST_DEFINE(), and cdr_read_callback().

03067 {
03068    RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
03069    struct cdr_object *cdr_obj;
03070 
03071    if (!cdr) {
03072       ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
03073       return 1;
03074    }
03075 
03076    if (ast_strlen_zero(name)) {
03077       return 1;
03078    }
03079 
03080    ao2_lock(cdr);
03081 
03082    cdr_obj = cdr->last;
03083    if (cdr_object_format_property(cdr_obj, name, value, length)) {
03084       /* Property failed; attempt variable */
03085       cdr_object_format_var_internal(cdr_obj, name, value, length);
03086    }
03087 
03088    ao2_unlock(cdr);
03089 
03090    return 0;
03091 }

int ast_cdr_is_enabled ( void   ) 

Return TRUE if CDR subsystem is enabled.

Definition at line 2629 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ast_test_flag, CDR_ENABLED, and RAII_VAR.

Referenced by action_coresettings(), and handle_show_settings().

02630 {
02631    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
02632    return ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED);
02633 }

struct stasis_message_router* ast_cdr_message_router ( void   )  [read]

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:
NULL if the CDR engine is disabled or unavailable
the stasis_message_router otherwise

Definition at line 3974 of file cdr.c.

References ao2_bump, NULL, and stasis_router.

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

03975 {
03976    if (!stasis_router) {
03977       return NULL;
03978    }
03979 
03980    ao2_bump(stasis_router);
03981    return stasis_router;
03982 }

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

Register a CDR handling engine.

Parameters:
name name associated with the particular CDR handler
desc description of the CDR handler
be function pointer to a CDR handler Used to register a Call Detail Record handler.
Return values:
0 on success.
-1 on error

Definition at line 2671 of file cdr.c.

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

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

02672 {
02673    struct cdr_beitem *i = NULL;
02674 
02675    if (!name)
02676       return -1;
02677 
02678    if (!be) {
02679       ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
02680       return -1;
02681    }
02682 
02683    AST_RWLIST_WRLOCK(&be_list);
02684    AST_RWLIST_TRAVERSE(&be_list, i, list) {
02685       if (!strcasecmp(name, i->name)) {
02686          ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
02687          AST_RWLIST_UNLOCK(&be_list);
02688          return -1;
02689       }
02690    }
02691 
02692    if (!(i = ast_calloc(1, sizeof(*i))))
02693       return -1;
02694 
02695    i->be = be;
02696    ast_copy_string(i->name, name, sizeof(i->name));
02697    ast_copy_string(i->desc, desc, sizeof(i->desc));
02698 
02699    AST_RWLIST_INSERT_HEAD(&be_list, i, list);
02700    AST_RWLIST_UNLOCK(&be_list);
02701 
02702    return 0;
02703 }

int ast_cdr_reset ( const char *  channel_name,
int  keep_variables 
)

Reset the detail record.

Parameters:
channel_name The channel that the CDR is associated with
keep_variables Keep the variables during the reset. If zero, variables are discarded during the reset.
Return values:
0 on success
-1 on failure

Definition at line 3318 of file cdr.c.

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::next, cdr_object::party_a, cdr_object::party_b, RAII_VAR, cdr_object::start, and cdr_object_snapshot::variables.

Referenced by appcdr_callback(), and dial_exec_full().

03319 {
03320    RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
03321    struct ast_var_t *vardata;
03322    struct cdr_object *it_cdr;
03323 
03324    if (!cdr) {
03325       return -1;
03326    }
03327 
03328    ao2_lock(cdr);
03329    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
03330       /* clear variables */
03331       if (!keep_variables) {
03332          while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_a.variables, entries))) {
03333             ast_var_delete(vardata);
03334          }
03335          if (cdr->party_b.snapshot) {
03336             while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_b.variables, entries))) {
03337                ast_var_delete(vardata);
03338             }
03339          }
03340       }
03341 
03342       /* Reset to initial state */
03343       memset(&it_cdr->start, 0, sizeof(it_cdr->start));
03344       memset(&it_cdr->end, 0, sizeof(it_cdr->end));
03345       memset(&it_cdr->answer, 0, sizeof(it_cdr->answer));
03346       it_cdr->start = ast_tvnow();
03347       cdr_object_check_party_a_answer(it_cdr);
03348    }
03349    ao2_unlock(cdr);
03350 
03351    return 0;
03352 }

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_name The channel to get the CDR for
buf A buffer to use for formatting the data
delim A delimeter to use to separate variable keys/values
sep A separator to use between nestings
Return values:
the total number of serialized variables

Definition at line 3093 of file cdr.c.

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

Referenced by handle_showchan().

03094 {
03095    RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
03096    struct cdr_object *it_cdr;
03097    struct ast_var_t *variable;
03098    const char *var;
03099    RAII_VAR(char *, workspace, ast_malloc(256), ast_free);
03100    int total = 0, x = 0, i;
03101 
03102    if (!workspace) {
03103       return 0;
03104    }
03105 
03106    if (!cdr) {
03107       RAII_VAR(struct module_config *, mod_cfg,
03108           ao2_global_obj_ref(module_configs), ao2_cleanup);
03109 
03110       if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
03111          ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
03112       }
03113 
03114       return 0;
03115    }
03116 
03117    ast_str_reset(*buf);
03118 
03119    ao2_lock(cdr);
03120    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
03121       if (++x > 1)
03122          ast_str_append(buf, 0, "\n");
03123 
03124       AST_LIST_TRAVERSE(&it_cdr->party_a.variables, variable, entries) {
03125          if (!(var = ast_var_name(variable))) {
03126             continue;
03127          }
03128 
03129          if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variable), ""), sep) < 0) {
03130             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
03131             break;
03132          }
03133 
03134          total++;
03135       }
03136 
03137       for (i = 0; cdr_readonly_vars[i]; i++) {
03138          if (cdr_object_format_property(it_cdr, cdr_readonly_vars[i], workspace, sizeof(workspace))) {
03139             /* Unhandled read-only CDR variable. */
03140             ast_assert(0);
03141             continue;
03142          }
03143 
03144          if (!ast_strlen_zero(workspace)
03145             && ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, workspace, sep) < 0) {
03146             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
03147             break;
03148          }
03149          total++;
03150       }
03151    }
03152    ao2_unlock(cdr);
03153    return total;
03154 }

void ast_cdr_set_config ( struct ast_cdr_config config  ) 

Set the current CDR configuration.

Since:
12
Parameters:
config The new CDR configuration

Definition at line 2618 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ao2_ref, cdr_toggle_runtime_options(), and RAII_VAR.

Referenced by test_cdr_cleanup_cb().

02619 {
02620    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
02621 
02622    ao2_cleanup(mod_cfg->general);
02623    mod_cfg->general = config;
02624    ao2_ref(mod_cfg->general, +1);
02625 
02626    cdr_toggle_runtime_options();
02627 }

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 enum ast_cdr_options for more information.
Parameters:
channel_name The CDR's channel
option Option to apply to the CDR
Return values:
0 on success
1 on error

Definition at line 3272 of file cdr.c.

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, cdr_object::party_a, and RAII_VAR.

Referenced by appcdr_callback(), AST_TEST_DEFINE(), and cdr_prop_write_callback().

03273 {
03274    RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
03275    struct cdr_object *it_cdr;
03276 
03277    if (!cdr) {
03278       return -1;
03279    }
03280 
03281    ao2_lock(cdr);
03282    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
03283       if (it_cdr->fn_table == &finalized_state_fn_table) {
03284          continue;
03285       }
03286       /* Note: in general, set the flags on both the CDR record as well as the
03287        * Party A. Sometimes all we have is the Party A to look at.
03288        */
03289       ast_set_flag(&it_cdr->flags, option);
03290       ast_set_flag(&it_cdr->party_a, option);
03291    }
03292    ao2_unlock(cdr);
03293 
03294    return 0;
03295 }

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

Set CDR user field for channel (stored in CDR).

Parameters:
channel_name The name of the channel that owns the CDR
userfield The user field to set

Definition at line 3217 of file cdr.c.

References active_cdrs_by_channel, ao2_callback, ao2_cleanup, ao2_lock, ao2_unlock, 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, OBJ_NODATA, cdr_object::party_a, RAII_VAR, and cdr_object_snapshot::userfield.

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

03218 {
03219    RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
03220    struct party_b_userfield_update party_b_info = {
03221          .channel_name = channel_name,
03222          .userfield = userfield,
03223    };
03224    struct cdr_object *it_cdr;
03225 
03226    /* Handle Party A */
03227    if (cdr) {
03228       ao2_lock(cdr);
03229       for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
03230          if (it_cdr->fn_table == &finalized_state_fn_table) {
03231             continue;
03232          }
03233          strcpy(it_cdr->party_a.userfield, userfield);
03234       }
03235       ao2_unlock(cdr);
03236    }
03237 
03238    /* Handle Party B */
03239    ao2_callback(active_cdrs_by_channel, OBJ_NODATA,
03240          cdr_object_update_party_b_userfield_cb,
03241          &party_b_info);
03242 
03243 }

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

Set a variable on a CDR.

Since:
12
Parameters:
channel_name The channel to set the variable on
name The name of the variable to set
value The value of the variable to set
Return values:
0 on success
non-zero on failure

Definition at line 2920 of file cdr.c.

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

Referenced by AST_TEST_DEFINE(), and cdr_write_callback().

02921 {
02922    struct cdr_object *cdr;
02923    struct cdr_object *it_cdr;
02924    struct ao2_iterator *it_cdrs;
02925    char *arg = ast_strdupa(channel_name);
02926    int x;
02927 
02928    for (x = 0; cdr_readonly_vars[x]; x++) {
02929       if (!strcasecmp(name, cdr_readonly_vars[x])) {
02930          ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!\n", name);
02931          return -1;
02932       }
02933    }
02934 
02935    it_cdrs = ao2_callback(active_cdrs_by_channel, OBJ_MULTIPLE, cdr_object_select_all_by_name_cb, arg);
02936    if (!it_cdrs) {
02937       ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
02938       return -1;
02939    }
02940 
02941    for (; (cdr = ao2_iterator_next(it_cdrs)); ao2_unlock(cdr), ao2_cleanup(cdr)) {
02942       ao2_lock(cdr);
02943       for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
02944          struct varshead *headp = NULL;
02945 
02946          if (it_cdr->fn_table == &finalized_state_fn_table) {
02947             continue;
02948          }
02949          if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->name)) {
02950             headp = &it_cdr->party_a.variables;
02951          } else if (it_cdr->party_b.snapshot
02952             && !strcasecmp(channel_name, it_cdr->party_b.snapshot->name)) {
02953             headp = &it_cdr->party_b.variables;
02954          }
02955          if (headp) {
02956             set_variable(headp, name, value);
02957          }
02958       }
02959    }
02960    ao2_iterator_destroy(it_cdrs);
02961 
02962    return 0;
02963 }

int ast_cdr_unregister ( const char *  name  ) 

Unregister a CDR handling engine.

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

Definition at line 2705 of file cdr.c.

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

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

02706 {
02707    struct cdr_beitem *match = NULL;
02708    int active_count;
02709 
02710    AST_RWLIST_WRLOCK(&be_list);
02711    AST_RWLIST_TRAVERSE(&be_list, match, list) {
02712       if (!strcasecmp(name, match->name)) {
02713          break;
02714       }
02715    }
02716 
02717    if (!match) {
02718       AST_RWLIST_UNLOCK(&be_list);
02719       return 0;
02720    }
02721 
02722    active_count = ao2_container_count(active_cdrs_by_channel);
02723 
02724    if (!match->suspended && active_count != 0) {
02725       AST_RWLIST_UNLOCK(&be_list);
02726       ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
02727          name, active_count);
02728       return -1;
02729    }
02730 
02731    AST_RWLIST_REMOVE(&be_list, match, list);
02732    AST_RWLIST_UNLOCK(&be_list);
02733 
02734    ast_verb(2, "Unregistered '%s' CDR backend\n", name);
02735    ast_free(match);
02736 
02737    return 0;
02738 }

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

References BRIDGE_ENTER_NEED_CDR.

01411 {
01412    /* Base process bridge enter simply indicates that we can't handle it */
01413    return BRIDGE_ENTER_NEED_CDR;
01414 }

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

Definition at line 1396 of file cdr.c.

References ast_assert.

01397 {
01398    /* In general, most things shouldn't get a bridge leave */
01399    ast_assert(0);
01400    return 1;
01401 }

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

References ast_assert.

01404 {
01405    /* In general, most things shouldn't get a dial end. */
01406    ast_assert(0);
01407    return 0;
01408 }

static int base_process_parked_channel ( struct cdr_object cdr,
struct ast_parked_call_payload parking_info 
) [static]

Definition at line 1416 of file cdr.c.

References ast_assert, AST_CDR_LOCK_APP, ast_set_flag, ast_string_field_set, cdr_object::flags, cdr_object::fn_table, ast_channel_snapshot::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.

01417 {
01418    char park_info[128];
01419 
01420    ast_assert(!strcasecmp(parking_info->parkee->name, cdr->party_a.snapshot->name));
01421 
01422    /* Update Party A information regardless */
01423    cdr->fn_table->process_party_a(cdr, parking_info->parkee);
01424 
01425    /* Fake out where we're parked */
01426    ast_string_field_set(cdr, appl, "Park");
01427    snprintf(park_info, sizeof(park_info), "%s:%u", parking_info->parkinglot, parking_info->parkingspace);
01428    ast_string_field_set(cdr, data, park_info);
01429 
01430    /* Prevent any further changes to the App/Data fields for this record */
01431    ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
01432 
01433    return 0;
01434 }

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

Definition at line 1343 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, cdr_object::appl, ast_channel_snapshot::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, CDR_END_BEFORE_H_EXTEN, cdr_object_check_party_a_answer(), cdr_object_check_party_a_hangup(), cdr_object_swap_snapshot(), ast_channel_snapshot::context, context, ast_channel_snapshot::data, ast_channel_snapshot::exten, exten, cdr_object::flags, ast_channel_snapshot::flags, ast_channel_snapshot::linkedid, ast_cdr::linkedid, ast_channel_snapshot::name, cdr_object::party_a, RAII_VAR, cdr_object_snapshot::snapshot, and ast_channel_snapshot::softhangup_flags.

Referenced by dialed_pending_state_process_party_a(), and single_state_process_dial_begin().

01344 {
01345    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
01346 
01347    ast_assert(strcasecmp(snapshot->name, cdr->party_a.snapshot->name) == 0);
01348 
01349    /* Ignore any snapshots from a dead or dying channel */
01350    if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
01351          && ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)) {
01352       cdr_object_check_party_a_hangup(cdr);
01353       return 0;
01354    }
01355 
01356    /*
01357     * Only record the context and extension if we aren't in a subroutine, or if
01358     * we are executing hangup logic.
01359     */
01360    if (!ast_test_flag(&snapshot->flags, AST_FLAG_SUBROUTINE_EXEC)
01361       || ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) {
01362       ast_string_field_set(cdr, context, snapshot->context);
01363       ast_string_field_set(cdr, exten, snapshot->exten);
01364    }
01365 
01366    cdr_object_swap_snapshot(&cdr->party_a, snapshot);
01367 
01368    /* When Party A is originated to an application and the application exits, the stack
01369     * will attempt to clear the application and restore the dummy originate application
01370     * of "AppDialX". Prevent that, and any other application changes we might not want
01371     * here.
01372     */
01373    if (!ast_strlen_zero(snapshot->appl)
01374          && (strncasecmp(snapshot->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))
01375          && !ast_test_flag(&cdr->flags, AST_CDR_LOCK_APP)) {
01376       ast_string_field_set(cdr, appl, snapshot->appl);
01377       ast_string_field_set(cdr, data, snapshot->data);
01378 
01379       /* Dial (app_dial) is a special case. Because pre-dial handlers, which
01380        * execute before the dial begins, will alter the application/data to
01381        * something people typically don't want to see, if we see a channel enter
01382        * into Dial here, we set the appl/data accordingly and lock it.
01383        */
01384       if (!strcmp(snapshot->appl, "Dial")) {
01385          ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
01386       }
01387    }
01388 
01389    ast_string_field_set(cdr, linkedid, snapshot->linkedid);
01390    cdr_object_check_party_a_answer(cdr);
01391    cdr_object_check_party_a_hangup(cdr);
01392 
01393    return 0;
01394 }

static void bridge_candidate_add_to_cdr ( struct cdr_object cdr,
struct cdr_object_snapshot party_b 
) [static]

Definition at line 2257 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ast_string_field_set, cdr_object::bridge, bridge_state_fn_table, CDR_DEBUG, cdr_object_check_party_a_answer(), cdr_object_create_and_append(), cdr_object_snapshot_copy(), cdr_object_transition_state(), ast_channel_snapshot::name, cdr_object::party_a, cdr_object::party_b, RAII_VAR, and cdr_object_snapshot::snapshot.

Referenced by bridge_candidate_process().

02259 {
02260    RAII_VAR(struct module_config *,  mod_cfg,
02261       ao2_global_obj_ref(module_configs), ao2_cleanup);
02262    struct cdr_object *new_cdr;
02263 
02264    new_cdr = cdr_object_create_and_append(cdr);
02265    if (!new_cdr) {
02266       return;
02267    }
02268    cdr_object_snapshot_copy(&new_cdr->party_b, party_b);
02269    cdr_object_check_party_a_answer(new_cdr);
02270    ast_string_field_set(new_cdr, bridge, cdr->bridge);
02271    cdr_object_transition_state(new_cdr, &bridge_state_fn_table);
02272    CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
02273       new_cdr, new_cdr->party_a.snapshot->name,
02274       party_b->snapshot->name);
02275 }

static int 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:
cdr The cdr_obj being processed
cand_cdr The cdr_object that is a candidate

Definition at line 2289 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, cdr_object::bridge, bridge_candidate_add_to_cdr(), CDR_DEBUG, cdr_object_pick_party_a(), cdr_object_snapshot_copy(), cdr_object::end, lock, ast_channel_snapshot::name, cdr_object::next, cdr_object::party_a, cdr_object::party_b, RAII_VAR, SCOPED_AO2LOCK, and cdr_object_snapshot::snapshot.

Referenced by handle_bridge_pairings().

02290 {
02291    RAII_VAR(struct module_config *, mod_cfg,
02292       ao2_global_obj_ref(module_configs), ao2_cleanup);
02293    struct cdr_object_snapshot *party_a;
02294    struct cdr_object *cand_cdr;
02295 
02296    SCOPED_AO2LOCK(lock, base_cand_cdr);
02297 
02298    for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->next) {
02299       /* Skip any records that are not in this bridge */
02300       if (strcmp(cand_cdr->bridge, cdr->bridge)) {
02301          continue;
02302       }
02303 
02304       /* If the candidate is us or someone we've taken on, pass on by */
02305       if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)
02306          || (cdr->party_b.snapshot
02307             && !strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name))) {
02308          return 0;
02309       }
02310 
02311       party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
02312       /* We're party A - make a new CDR, append it to us, and set the candidate as
02313        * Party B */
02314       if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
02315          bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
02316          return 0;
02317       }
02318 
02319       /* We're Party B. Check if we can add ourselves immediately or if we need
02320        * a new CDR for them (they already have a Party B) */
02321       if (cand_cdr->party_b.snapshot
02322          && strcasecmp(cand_cdr->party_b.snapshot->name, cdr->party_a.snapshot->name)) {
02323          bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a);
02324       } else {
02325          CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
02326             cand_cdr, cand_cdr->party_a.snapshot->name,
02327             cdr->party_a.snapshot->name);
02328          cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
02329          /* It's possible that this joined at one point and was never chosen
02330           * as party A. Clear their end time, as it would be set in such a
02331           * case.
02332           */
02333          memset(&cand_cdr->end, 0, sizeof(cand_cdr->end));
02334       }
02335       return 0;
02336    }
02337    return 0;
02338 }

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

References cdr_object::bridge, cdr_object_transition_state(), finalized_state_fn_table, ast_channel_snapshot::name, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, and ast_bridge_snapshot::uniqueid.

01816 {
01817    if (strcmp(cdr->bridge, bridge->uniqueid)) {
01818       return 1;
01819    }
01820    if (strcasecmp(cdr->party_a.snapshot->name, channel->name)
01821       && cdr->party_b.snapshot
01822       && strcasecmp(cdr->party_b.snapshot->name, channel->name)) {
01823       return 1;
01824    }
01825    cdr_object_transition_state(cdr, &finalized_state_fn_table);
01826 
01827    return 0;
01828 }

static void bridge_state_process_party_b ( struct cdr_object cdr,
struct ast_channel_snapshot snapshot 
) [static]

Definition at line 1801 of file cdr.c.

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

01802 {
01803    if (!cdr->party_b.snapshot
01804       || strcasecmp(cdr->party_b.snapshot->name, snapshot->name)) {
01805       return;
01806    }
01807    cdr_object_swap_snapshot(&cdr->party_b, snapshot);
01808 
01809    /* If party B hangs up, finalize this CDR */
01810    if (ast_test_flag(&cdr->party_b.snapshot->flags, AST_FLAG_DEAD)) {
01811       cdr_object_transition_state(cdr, &finalized_state_fn_table);
01812    }
01813 }

static void cdr_container_print_fn ( void *  v_obj,
void *  where,
ao2_prnt_fn prnt 
) [static]

Definition at line 4126 of file cdr.c.

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

Referenced by ast_cdr_engine_init().

04127 {
04128    struct cdr_object *cdr = v_obj;
04129    struct cdr_object *it_cdr;
04130    if (!cdr) {
04131       return;
04132    }
04133    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
04134       prnt(where, "Party A: %s; Party B: %s; Bridge %s\n", it_cdr->party_a.snapshot->name, it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<unknown>",
04135             it_cdr->bridge);
04136    }
04137 }

static void cdr_detach ( struct ast_cdr cdr  )  [static]

Definition at line 3542 of file cdr.c.

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, submit_unscheduled_batch(), and cdr_batch::tail.

Referenced by cdr_object_dispatch().

03543 {
03544    struct cdr_batch_item *newtail;
03545    int curr;
03546    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
03547    int submit_batch = 0;
03548 
03549    if (!cdr) {
03550       return;
03551    }
03552 
03553    /* maybe they disabled CDR stuff completely, so just drop it */
03554    if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
03555       ast_debug(1, "Dropping CDR !\n");
03556       ast_cdr_free(cdr);
03557       return;
03558    }
03559 
03560    /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
03561    if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
03562       post_cdr(cdr);
03563       ast_cdr_free(cdr);
03564       return;
03565    }
03566 
03567    /* otherwise, each CDR gets put into a batch list (at the end) */
03568    ast_debug(1, "CDR detaching from this thread\n");
03569 
03570    /* we'll need a new tail for every CDR */
03571    if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
03572       post_cdr(cdr);
03573       ast_cdr_free(cdr);
03574       return;
03575    }
03576 
03577    /* don't traverse a whole list (just keep track of the tail) */
03578    ast_mutex_lock(&cdr_batch_lock);
03579    if (!batch)
03580       init_batch();
03581    if (!batch->head) {
03582       /* new batch is empty, so point the head at the new tail */
03583       batch->head = newtail;
03584    } else {
03585       /* already got a batch with something in it, so just append a new tail */
03586       batch->tail->next = newtail;
03587    }
03588    newtail->cdr = cdr;
03589    batch->tail = newtail;
03590    curr = batch->size++;
03591 
03592    /* if we have enough stuff to post, then do it */
03593    if (curr >= (mod_cfg->general->batch_settings.size - 1)) {
03594       submit_batch = 1;
03595    }
03596    ast_mutex_unlock(&cdr_batch_lock);
03597 
03598    /* Don't call submit_unscheduled_batch with the cdr_batch_lock held */
03599    if (submit_batch) {
03600       submit_unscheduled_batch();
03601    }
03602 }

static void cdr_enable_batch_mode ( struct ast_cdr_config config  )  [static]

Definition at line 4095 of file cdr.c.

References ast_cond_init, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_background, AST_PTHREADT_NULL, ast_sched_add(), AST_SCHED_DEL, batch, ast_cdr_config::batch_settings, cdr_batch_lock, cdr_pending_cond, cdr_sched, cdr_thread, do_cdr(), LOG_ERROR, LOG_NOTICE, NULL, SCOPED_LOCK, ast_cdr_config::batch_settings::size, submit_scheduled_batch(), and ast_cdr_config::batch_settings::time.

Referenced by cdr_toggle_runtime_options().

04096 {
04097    SCOPED_LOCK(batch, &cdr_batch_lock, ast_mutex_lock, ast_mutex_unlock);
04098 
04099    /* Only create the thread level portions once */
04100    if (cdr_thread == AST_PTHREADT_NULL) {
04101       ast_cond_init(&cdr_pending_cond, NULL);
04102       if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
04103          ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
04104          return;
04105       }
04106    }
04107 
04108    /* Kill the currently scheduled item */
04109    AST_SCHED_DEL(sched, cdr_sched);
04110    cdr_sched = ast_sched_add(sched, config->batch_settings.time * 1000, submit_scheduled_batch, NULL);
04111    ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %u or time %u seconds.\n",
04112          config->batch_settings.size, config->batch_settings.time);
04113 }

static void cdr_engine_cleanup ( void   )  [static]

Definition at line 4063 of file cdr.c.

References destroy_subscriptions().

Referenced by ast_cdr_engine_init().

04064 {
04065    destroy_subscriptions();
04066 }

static void cdr_engine_shutdown ( void   )  [static]

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

Definition at line 2760 of file cdr.c.

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

Referenced by ast_cdr_format_var().

02761 {
02762    struct ast_var_t *variables;
02763 
02764    if (ast_strlen_zero(name)) {
02765       return NULL;
02766    }
02767 
02768    AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
02769       if (!strcasecmp(name, ast_var_name(variables))) {
02770          return ast_var_value(variables);
02771       }
02772    }
02773 
02774    return NULL;
02775 }

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

Definition at line 2777 of file cdr.c.

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

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

02778 {
02779    if (fmt == NULL) {   /* raw mode */
02780       snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
02781    } else {
02782       buf[0] = '\0';/* Ensure the buffer is initialized. */
02783       if (when.tv_sec) {
02784          struct ast_tm tm;
02785 
02786          ast_localtime(&when, &tm, NULL);
02787          ast_strftime(buf, bufsize, fmt, &tm);
02788       }
02789    }
02790 }

static struct cdr_object* cdr_object_alloc ( struct ast_channel_snapshot chan  )  [static, read]

cdr_object constructor

Parameters:
chan The ast_channel_snapshot that is the CDR's Party A
This implicitly sets the state of the newly created CDR to the Single state (single_state_fn_table)

Definition at line 862 of file cdr.c.

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

Referenced by cdr_object_create_and_append(), and handle_channel_cache_message().

00863 {
00864    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
00865    struct cdr_object *cdr;
00866 
00867    ast_assert(chan != NULL);
00868 
00869    cdr = ao2_alloc(sizeof(*cdr), cdr_object_dtor);
00870    if (!cdr) {
00871       return NULL;
00872    }
00873    cdr->last = cdr;
00874    if (ast_string_field_init(cdr, 64)) {
00875       ao2_cleanup(cdr);
00876       return NULL;
00877    }
00878    ast_string_field_set(cdr, uniqueid, chan->uniqueid);
00879    ast_string_field_set(cdr, name, chan->name);
00880    ast_string_field_set(cdr, linkedid, chan->linkedid);
00881    cdr->disposition = AST_CDR_NULL;
00882    cdr->sequence = ast_atomic_fetchadd_int(&global_cdr_sequence, +1);
00883 
00884    cdr->party_a.snapshot = chan;
00885    ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
00886 
00887    CDR_DEBUG(mod_cfg, "%p - Created CDR for channel %s\n", cdr, chan->name);
00888 
00889    cdr_object_transition_state(cdr, &single_state_fn_table);
00890 
00891    return cdr;
00892 }

static int cdr_object_channel_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 804 of file cdr.c.

References ast_assert, CMP_MATCH, OBJ_KEY, OBJ_PARTIAL_KEY, OBJ_POINTER, and cdr_object::uniqueid.

Referenced by ast_cdr_engine_init().

00805 {
00806     struct cdr_object *left = obj;
00807     struct cdr_object *right = arg;
00808     const char *right_key = arg;
00809     int cmp;
00810 
00811     switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
00812     case OBJ_POINTER:
00813         right_key = right->uniqueid;
00814         /* Fall through */
00815     case OBJ_KEY:
00816         cmp = strcmp(left->uniqueid, right_key);
00817         break;
00818     case OBJ_PARTIAL_KEY:
00819         /*
00820          * We could also use a partial key struct containing a length
00821          * so strlen() does not get called for every comparison instead.
00822          */
00823         cmp = strncmp(left->uniqueid, right_key, strlen(right_key));
00824         break;
00825     default:
00826         /* Sort can only work on something with a full or partial key. */
00827         ast_assert(0);
00828         cmp = 0;
00829         break;
00830     }
00831     return cmp ? 0 : CMP_MATCH;
00832 }

static int cdr_object_channel_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 781 of file cdr.c.

References ast_assert, ast_str_case_hash(), OBJ_KEY, OBJ_PARTIAL_KEY, OBJ_POINTER, and cdr_object::uniqueid.

Referenced by ast_cdr_engine_init().

00782 {
00783    const struct cdr_object *cdr;
00784    const char *key;
00785 
00786    switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
00787    case OBJ_KEY:
00788       key = obj;
00789       break;
00790    case OBJ_POINTER:
00791       cdr = obj;
00792       key = cdr->uniqueid;
00793       break;
00794    default:
00795       ast_assert(0);
00796       return 0;
00797    }
00798    return ast_str_case_hash(key);
00799 }

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

References cdr_object::answer, ao2_cleanup, ao2_global_obj_ref, AST_STATE_UP, ast_tvnow(), ast_tvzero(), CDR_DEBUG, cdr_object::party_a, RAII_VAR, 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().

01292                                                                     {
01293    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
01294 
01295    if (cdr->party_a.snapshot->state == AST_STATE_UP && ast_tvzero(cdr->answer)) {
01296       cdr->answer = ast_tvnow();
01297       /* tv_usec is suseconds_t, which could be int or long */
01298       CDR_DEBUG(mod_cfg, "%p - Set answered time to %ld.%06ld\n", cdr,
01299          (long)cdr->answer.tv_sec,
01300          (long)cdr->answer.tv_usec);
01301    }
01302 }

static void cdr_object_check_party_a_hangup ( struct cdr_object cdr  )  [static]

static struct cdr_object* cdr_object_create_and_append ( struct cdr_object cdr  )  [static, read]

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

Parameters:
cdr The cdr_object to append to

Definition at line 898 of file cdr.c.

References cdr_object::appl, AST_CDR_NULL, ast_string_field_set, cdr_object_alloc(), cdr_object_snapshot_copy(), cdr_object::data, cdr_object::disposition, 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_cache_message(), handle_dial_message(), handle_parked_call_message(), handle_parking_bridge_enter_message(), and handle_standard_bridge_enter_message().

00899 {
00900    struct cdr_object *new_cdr;
00901    struct cdr_object *it_cdr;
00902    struct cdr_object *cdr_last;
00903 
00904    cdr_last = cdr->last;
00905    new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot);
00906    if (!new_cdr) {
00907       return NULL;
00908    }
00909    new_cdr->disposition = AST_CDR_NULL;
00910 
00911    /* Copy over the linkedid, as it may have changed */
00912    ast_string_field_set(new_cdr, linkedid, cdr_last->linkedid);
00913    ast_string_field_set(new_cdr, appl, cdr_last->appl);
00914    ast_string_field_set(new_cdr, data, cdr_last->data);
00915 
00916    /* Copy over other Party A information */
00917    cdr_object_snapshot_copy(&new_cdr->party_a, &cdr_last->party_a);
00918 
00919    /* Append the CDR to the end of the list */
00920    for (it_cdr = cdr; it_cdr->next; it_cdr = it_cdr->next) {
00921       it_cdr->last = new_cdr;
00922    }
00923    it_cdr->last = new_cdr;
00924    it_cdr->next = new_cdr;
00925 
00926    return new_cdr;
00927 }

static struct ast_cdr* cdr_object_create_public_records ( struct cdr_object cdr  )  [static, read]

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

Parameters:
cdr The cdr_object to convert to a public record
Return values:
A chain of ast_cdr objects on success
NULL on failure

Definition at line 1080 of file cdr.c.

References ast_channel_snapshot::accountcode, ast_cdr::accountcode, ast_channel_snapshot::amaflags, ast_cdr::amaflags, cdr_object::answer, ast_cdr::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_cdr::billsec, ast_channel_snapshot::caller_name, ast_channel_snapshot::caller_number, 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, cdr_object::disposition, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, cdr_object::end, ast_cdr::end, ast_var_t::entries, cdr_object::exten, cdr_object::flags, ast_cdr::lastapp, ast_cdr::lastdata, cdr_object::linkedid, ast_cdr::linkedid, ast_channel_snapshot::name, ast_cdr::next, cdr_object::next, NULL, cdr_object::party_a, cdr_object::party_b, ast_cdr::peeraccount, cdr_object::sequence, ast_cdr::sequence, cdr_object_snapshot::snapshot, snapshot_is_dialed(), ast_cdr::src, cdr_object::start, ast_cdr::start, ast_channel_snapshot::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, cdr_object_snapshot::userfield, cdr_object_snapshot::variables, and ast_cdr::varshead.

Referenced by cdr_object_dispatch().

01081 {
01082    struct ast_cdr *pub_cdr = NULL, *cdr_prev = NULL;
01083    struct cdr_object *it_cdr;
01084    struct ast_var_t *it_var, *it_copy_var;
01085    struct ast_channel_snapshot *party_a;
01086    struct ast_channel_snapshot *party_b;
01087 
01088    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
01089       struct ast_cdr *cdr_copy;
01090 
01091       /* Don't create records for CDRs where the party A was a dialed channel */
01092       if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
01093          ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
01094             it_cdr->party_a.snapshot->name);
01095          continue;
01096       }
01097 
01098       cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
01099       if (!cdr_copy) {
01100          ast_free(pub_cdr);
01101          return NULL;
01102       }
01103 
01104       party_a = it_cdr->party_a.snapshot;
01105       party_b = it_cdr->party_b.snapshot;
01106 
01107       /* Party A */
01108       ast_assert(party_a != NULL);
01109       ast_copy_string(cdr_copy->accountcode, party_a->accountcode, sizeof(cdr_copy->accountcode));
01110       cdr_copy->amaflags = party_a->amaflags;
01111       ast_copy_string(cdr_copy->channel, party_a->name, sizeof(cdr_copy->channel));
01112       ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller_name, party_a->caller_number, "");
01113       ast_copy_string(cdr_copy->src, party_a->caller_number, sizeof(cdr_copy->src));
01114       ast_copy_string(cdr_copy->uniqueid, party_a->uniqueid, sizeof(cdr_copy->uniqueid));
01115       ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
01116       ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
01117       ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
01118       ast_copy_string(cdr_copy->dcontext, it_cdr->context, sizeof(cdr_copy->dcontext));
01119 
01120       /* Party B */
01121       if (party_b) {
01122          ast_copy_string(cdr_copy->dstchannel, party_b->name, sizeof(cdr_copy->dstchannel));
01123          ast_copy_string(cdr_copy->peeraccount, party_b->accountcode, sizeof(cdr_copy->peeraccount));
01124          if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
01125             snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
01126          }
01127       }
01128       if (ast_strlen_zero(cdr_copy->userfield) && !ast_strlen_zero(it_cdr->party_a.userfield)) {
01129          ast_copy_string(cdr_copy->userfield, it_cdr->party_a.userfield, sizeof(cdr_copy->userfield));
01130       }
01131 
01132       /* Timestamps/durations */
01133       cdr_copy->start = it_cdr->start;
01134       cdr_copy->answer = it_cdr->answer;
01135       cdr_copy->end = it_cdr->end;
01136       cdr_copy->billsec = cdr_object_get_billsec(it_cdr);
01137       cdr_copy->duration = cdr_object_get_duration(it_cdr);
01138 
01139       /* Flags and IDs */
01140       ast_copy_flags(cdr_copy, &it_cdr->flags, AST_FLAGS_ALL);
01141       ast_copy_string(cdr_copy->linkedid, it_cdr->linkedid, sizeof(cdr_copy->linkedid));
01142       cdr_copy->disposition = it_cdr->disposition;
01143       cdr_copy->sequence = it_cdr->sequence;
01144 
01145       /* Variables */
01146       copy_variables(&cdr_copy->varshead, &it_cdr->party_a.variables);
01147       AST_LIST_TRAVERSE(&it_cdr->party_b.variables, it_var, entries) {
01148          int found = 0;
01149          struct ast_var_t *newvariable;
01150          AST_LIST_TRAVERSE(&cdr_copy->varshead, it_copy_var, entries) {
01151             if (!strcasecmp(ast_var_name(it_var), ast_var_name(it_copy_var))) {
01152                found = 1;
01153                break;
01154             }
01155          }
01156          if (!found && (newvariable = ast_var_assign(ast_var_name(it_var), ast_var_value(it_var)))) {
01157             AST_LIST_INSERT_TAIL(&cdr_copy->varshead, newvariable, entries);
01158          }
01159       }
01160 
01161       if (!pub_cdr) {
01162          pub_cdr = cdr_copy;
01163          cdr_prev = pub_cdr;
01164       } else {
01165          cdr_prev->next = cdr_copy;
01166          cdr_prev = cdr_copy;
01167       }
01168    }
01169 
01170    return pub_cdr;
01171 }

static void cdr_object_dispatch ( struct cdr_object cdr  )  [static]

Dispatch a CDR.

Parameters:
cdr The cdr_object to dispatch
This will create a ast_cdr object and publish it to the various backends

Definition at line 1179 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, CDR_DEBUG, cdr_detach(), cdr_object_create_public_records(), ast_channel_snapshot::name, cdr_object::party_a, cdr_object::party_b, RAII_VAR, and cdr_object_snapshot::snapshot.

Referenced by cdr_object_dispatch_all_cb(), and handle_channel_cache_message().

01180 {
01181    RAII_VAR(struct module_config *, mod_cfg,
01182          ao2_global_obj_ref(module_configs), ao2_cleanup);
01183    struct ast_cdr *pub_cdr;
01184 
01185    CDR_DEBUG(mod_cfg, "%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
01186          cdr->party_a.snapshot->name,
01187          cdr->party_b.snapshot ? cdr->party_b.snapshot->name : "<none>");
01188    pub_cdr = cdr_object_create_public_records(cdr);
01189    cdr_detach(pub_cdr);
01190 }

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

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

Definition at line 3945 of file cdr.c.

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

Referenced by cdr_engine_shutdown().

03946 {
03947    struct cdr_object *cdr = obj;
03948    struct cdr_object *it_cdr;
03949 
03950    ao2_lock(cdr);
03951    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
03952       cdr_object_transition_state(it_cdr, &finalized_state_fn_table);
03953    }
03954    cdr_object_dispatch(cdr);
03955    ao2_unlock(cdr);
03956 
03957    return 0;
03958 }

static void cdr_object_dtor ( void *  obj  )  [static]

cdr_object Destructor

Definition at line 837 of file cdr.c.

References ao2_cleanup, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_var_delete(), ast_var_t::entries, 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().

00838 {
00839    struct cdr_object *cdr = obj;
00840    struct ast_var_t *it_var;
00841 
00842    ao2_cleanup(cdr->party_a.snapshot);
00843    ao2_cleanup(cdr->party_b.snapshot);
00844    while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_a.variables, entries))) {
00845       ast_var_delete(it_var);
00846    }
00847    while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_b.variables, entries))) {
00848       ast_var_delete(it_var);
00849    }
00850    ast_string_field_free_memory(cdr);
00851 
00852    ao2_cleanup(cdr->next);
00853 }

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_object'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:
cdr_object The CDR to finalize

Definition at line 1238 of file cdr.c.

References cdr_object::answer, AST_CDR_ANSWERED, ast_cdr_disp2str(), AST_CDR_FAILED, AST_CDR_NULL, ast_debug, ast_tvnow(), ast_tvzero(), cdr_object_set_disposition(), cdr_object::disposition, cdr_object::end, ast_channel_snapshot::hangupcause, ast_channel_snapshot::name, cdr_object::party_a, cdr_object::party_b, cdr_object_snapshot::snapshot, and cdr_object::start.

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

01239 {
01240    if (!ast_tvzero(cdr->end)) {
01241       return;
01242    }
01243    cdr->end = ast_tvnow();
01244 
01245    if (cdr->disposition == AST_CDR_NULL) {
01246       if (!ast_tvzero(cdr->answer)) {
01247          cdr->disposition = AST_CDR_ANSWERED;
01248       } else if (cdr->party_a.snapshot->hangupcause) {
01249          cdr_object_set_disposition(cdr, cdr->party_a.snapshot->hangupcause);
01250       } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangupcause) {
01251          cdr_object_set_disposition(cdr, cdr->party_b.snapshot->hangupcause);
01252       } else {
01253          cdr->disposition = AST_CDR_FAILED;
01254       }
01255    }
01256 
01257    /* tv_usec is suseconds_t, which could be int or long */
01258    ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dispo %s\n",
01259          cdr->party_a.snapshot->name,
01260          (long)cdr->start.tv_sec,
01261          (long)cdr->start.tv_usec,
01262          (long)cdr->answer.tv_sec,
01263          (long)cdr->answer.tv_usec,
01264          (long)cdr->end.tv_sec,
01265          (long)cdr->end.tv_usec,
01266          ast_cdr_disp2str(cdr->disposition));
01267 }

static int cdr_object_finalize_party_b ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1991 of file cdr.c.

References cdr_object_finalize(), ast_channel_snapshot::name, cdr_object::next, cdr_object::party_b, and cdr_object_snapshot::snapshot.

Referenced by handle_channel_cache_message().

01992 {
01993    struct cdr_object *cdr = obj;
01994    struct ast_channel_snapshot *party_b = arg;
01995    struct cdr_object *it_cdr;
01996    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
01997       if (it_cdr->party_b.snapshot
01998          && !strcasecmp(it_cdr->party_b.snapshot->name, party_b->name)) {
01999          /* Don't transition to the finalized state - let the Party A do
02000           * that when its ready
02001           */
02002          cdr_object_finalize(it_cdr);
02003       }
02004    }
02005    return 0;
02006 }

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

References ast_channel_snapshot::accountcode, ast_channel_snapshot::amaflags, cdr_object::answer, ast_channel_snapshot::appl, ast_callerid_merge(), ast_copy_string(), ast_channel_snapshot::caller_name, ast_channel_snapshot::caller_number, cdr_get_tv(), cdr_object_get_billsec(), cdr_object_get_duration(), ast_channel_snapshot::context, ast_channel_snapshot::data, cdr_object::disposition, cdr_object::end, ast_channel_snapshot::exten, cdr_object::linkedid, ast_channel_snapshot::name, NULL, cdr_object::party_a, cdr_object::party_b, cdr_object::sequence, cdr_object_snapshot::snapshot, cdr_object::start, ast_channel_snapshot::uniqueid, and cdr_object_snapshot::userfield.

Referenced by ast_cdr_getvar(), and ast_cdr_serialize_variables().

02986 {
02987    struct ast_channel_snapshot *party_a = cdr_obj->party_a.snapshot;
02988    struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
02989 
02990    if (!strcasecmp(name, "clid")) {
02991       ast_callerid_merge(value, length, party_a->caller_name, party_a->caller_number, "");
02992    } else if (!strcasecmp(name, "src")) {
02993       ast_copy_string(value, party_a->caller_number, length);
02994    } else if (!strcasecmp(name, "dst")) {
02995       ast_copy_string(value, party_a->exten, length);
02996    } else if (!strcasecmp(name, "dcontext")) {
02997       ast_copy_string(value, party_a->context, length);
02998    } else if (!strcasecmp(name, "channel")) {
02999       ast_copy_string(value, party_a->name, length);
03000    } else if (!strcasecmp(name, "dstchannel")) {
03001       if (party_b) {
03002          ast_copy_string(value, party_b->name, length);
03003       } else {
03004          ast_copy_string(value, "", length);
03005       }
03006    } else if (!strcasecmp(name, "lastapp")) {
03007       ast_copy_string(value, party_a->appl, length);
03008    } else if (!strcasecmp(name, "lastdata")) {
03009       ast_copy_string(value, party_a->data, length);
03010    } else if (!strcasecmp(name, "start")) {
03011       cdr_get_tv(cdr_obj->start, NULL, value, length);
03012    } else if (!strcasecmp(name, "answer")) {
03013       cdr_get_tv(cdr_obj->answer, NULL, value, length);
03014    } else if (!strcasecmp(name, "end")) {
03015       cdr_get_tv(cdr_obj->end, NULL, value, length);
03016    } else if (!strcasecmp(name, "duration")) {
03017       snprintf(value, length, "%ld", cdr_object_get_duration(cdr_obj));
03018    } else if (!strcasecmp(name, "billsec")) {
03019       snprintf(value, length, "%ld", cdr_object_get_billsec(cdr_obj));
03020    } else if (!strcasecmp(name, "disposition")) {
03021       snprintf(value, length, "%u", cdr_obj->disposition);
03022    } else if (!strcasecmp(name, "amaflags")) {
03023       snprintf(value, length, "%d", party_a->amaflags);
03024    } else if (!strcasecmp(name, "accountcode")) {
03025       ast_copy_string(value, party_a->accountcode, length);
03026    } else if (!strcasecmp(name, "peeraccount")) {
03027       if (party_b) {
03028          ast_copy_string(value, party_b->accountcode, length);
03029       } else {
03030          ast_copy_string(value, "", length);
03031       }
03032    } else if (!strcasecmp(name, "uniqueid")) {
03033       ast_copy_string(value, party_a->uniqueid, length);
03034    } else if (!strcasecmp(name, "linkedid")) {
03035       ast_copy_string(value, cdr_obj->linkedid, length);
03036    } else if (!strcasecmp(name, "userfield")) {
03037       ast_copy_string(value, cdr_obj->party_a.userfield, length);
03038    } else if (!strcasecmp(name, "sequence")) {
03039       snprintf(value, length, "%u", cdr_obj->sequence);
03040    } else {
03041       return 1;
03042    }
03043 
03044    return 0;
03045 }

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

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

Referenced by ast_cdr_getvar().

02969 {
02970    struct ast_var_t *variable;
02971 
02972    AST_LIST_TRAVERSE(&cdr->party_a.variables, variable, entries) {
02973       if (!strcasecmp(name, ast_var_name(variable))) {
02974          ast_copy_string(value, ast_var_value(variable), length);
02975          return;
02976       }
02977    }
02978 
02979    *value = '\0';
02980 }

static long cdr_object_get_billsec ( struct cdr_object cdr  )  [static]

Compute the billsec for a cdr_object.

Definition at line 1028 of file cdr.c.

References cdr_object::answer, ao2_cleanup, ao2_global_obj_ref, ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), CDR_INITIATED_SECONDS, cdr_object::end, and RAII_VAR.

Referenced by cdr_object_create_public_records(), and cdr_object_format_property().

01029 {
01030    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
01031    long int ms;
01032 
01033    if (ast_tvzero(cdr->answer)) {
01034       return 0;
01035    }
01036    ms = ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->answer);
01037    if (ast_test_flag(&mod_cfg->general->settings, CDR_INITIATED_SECONDS)
01038       && (ms % 1000 >= 500)) {
01039       ms = (ms / 1000) + 1;
01040    } else {
01041       ms = ms / 1000;
01042    }
01043 
01044    return ms;
01045 }

static struct cdr_object* cdr_object_get_by_name ( const char *  name  )  [static, read]

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

Definition at line 2884 of file cdr.c.

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

Referenced by cdr_object_get_by_name().

02885 {
02886    struct cdr_object *cdr = obj;
02887    const char *name = arg;
02888 
02889    if (!strcasecmp(cdr->party_a.snapshot->name, name)) {
02890       return CMP_MATCH;
02891    }
02892    return 0;
02893 }

static long cdr_object_get_duration ( struct cdr_object cdr  )  [static]

Compute the duration for a cdr_object

Definition at line 1020 of file cdr.c.

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

01021 {
01022    return (long)(ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->start) / 1000);
01023 }

static int cdr_object_party_b_left_bridge_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

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

Definition at line 2142 of file cdr.c.

References bridge_leave_data::bridge, cdr_object::bridge, bridge_state_fn_table, cdr_object_finalize(), bridge_leave_data::channel, cdr_object::fn_table, ast_channel_snapshot::name, cdr_object::next, cdr_object::party_b, cdr_object_snapshot::snapshot, and ast_bridge_snapshot::uniqueid.

Referenced by handle_bridge_leave_message().

02143 {
02144    struct cdr_object *cdr = obj;
02145    struct bridge_leave_data *leave_data = arg;
02146    struct cdr_object *it_cdr;
02147 
02148    if (strcmp(cdr->bridge, leave_data->bridge->uniqueid)) {
02149       return 0;
02150    }
02151    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
02152       if (it_cdr->fn_table != &bridge_state_fn_table) {
02153          continue;
02154       }
02155       if (!it_cdr->party_b.snapshot) {
02156          continue;
02157       }
02158       if (strcasecmp(it_cdr->party_b.snapshot->name, leave_data->channel->name)) {
02159          continue;
02160       }
02161       /* It is our Party B, in our bridge. Set the end time and let the handler
02162        * transition our CDR appropriately when we leave the bridge.
02163        */
02164       cdr_object_finalize(it_cdr);
02165    }
02166    return 0;
02167 }

static struct cdr_object_snapshot* cdr_object_pick_party_a ( struct cdr_object_snapshot left,
struct cdr_object_snapshot right 
) [static, read]

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

Parameters:
left One of the snapshots
right The other snapshot
Return values:
The snapshot that won

Definition at line 985 of file cdr.c.

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

Referenced by bridge_candidate_process(), and single_state_bridge_enter_comparison().

00986 {
00987    /* Check whether or not the party is dialed. A dialed party is never the
00988     * Party A with a party that was not dialed.
00989     */
00990    if (!snapshot_is_dialed(left->snapshot) && snapshot_is_dialed(right->snapshot)) {
00991       return left;
00992    } else if (snapshot_is_dialed(left->snapshot) && !snapshot_is_dialed(right->snapshot)) {
00993       return right;
00994    }
00995 
00996    /* Try the Party A flag */
00997    if (ast_test_flag(left, AST_CDR_FLAG_PARTY_A) && !ast_test_flag(right, AST_CDR_FLAG_PARTY_A)) {
00998       return left;
00999    } else if (!ast_test_flag(right, AST_CDR_FLAG_PARTY_A) && ast_test_flag(right, AST_CDR_FLAG_PARTY_A)) {
01000       return right;
01001    }
01002 
01003    /* Neither party is dialed and neither has the Party A flag - defer to
01004     * creation time */
01005    if (left->snapshot->creationtime.tv_sec < right->snapshot->creationtime.tv_sec) {
01006       return left;
01007    } else if (left->snapshot->creationtime.tv_sec > right->snapshot->creationtime.tv_sec) {
01008       return right;
01009    } else if (left->snapshot->creationtime.tv_usec > right->snapshot->creationtime.tv_usec) {
01010       return right;
01011    } else {
01012       /* Okay, fine, take the left one */
01013       return left;
01014    }
01015 }

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

Definition at line 2868 of file cdr.c.

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

Referenced by ast_cdr_setvar().

02869 {
02870    struct cdr_object *cdr = obj;
02871    const char *name = arg;
02872 
02873    if (!strcasecmp(cdr->party_a.snapshot->name, name) ||
02874          (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->name, name))) {
02875       return CMP_MATCH;
02876    }
02877    return 0;
02878 }

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:
cdr The cdr_object
hangupcause The Asterisk hangup cause code

Definition at line 1197 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, 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, ast_test_flag, CDR_CONGESTION, cdr_object::disposition, and RAII_VAR.

Referenced by cdr_object_finalize().

01198 {
01199    RAII_VAR(struct module_config *, mod_cfg,
01200          ao2_global_obj_ref(module_configs), ao2_cleanup);
01201 
01202    /* Change the disposition based on the hang up cause */
01203    switch (hangupcause) {
01204    case AST_CAUSE_BUSY:
01205       cdr->disposition = AST_CDR_BUSY;
01206       break;
01207    case AST_CAUSE_CONGESTION:
01208       if (!ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION)) {
01209          cdr->disposition = AST_CDR_FAILED;
01210       } else {
01211          cdr->disposition = AST_CDR_CONGESTION;
01212       }
01213       break;
01214    case AST_CAUSE_NO_ROUTE_DESTINATION:
01215    case AST_CAUSE_UNREGISTERED:
01216       cdr->disposition = AST_CDR_FAILED;
01217       break;
01218    case AST_CAUSE_NORMAL_CLEARING:
01219    case AST_CAUSE_NO_ANSWER:
01220       cdr->disposition = AST_CDR_NOANSWER;
01221       break;
01222    default:
01223       break;
01224    }
01225 }

static void cdr_object_snapshot_copy ( struct cdr_object_snapshot dst,
struct cdr_object_snapshot src 
) [static]

Copy a snapshot and its details.

Parameters:
dst The destination
src The source

Definition at line 750 of file cdr.c.

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

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

00751 {
00752    if (dst->snapshot) {
00753       ao2_t_ref(dst->snapshot, -1, "release old snapshot during copy");
00754    }
00755    dst->snapshot = src->snapshot;
00756    ao2_t_ref(dst->snapshot, +1, "bump new snapshot during copy");
00757    strcpy(dst->userfield, src->userfield);
00758    dst->flags = src->flags;
00759    copy_variables(&dst->variables, &src->variables);
00760 }

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_snapshot The old cdr_object_snapshot
new_snapshot The new ast_channel_snapshot for old_snapshot

Definition at line 1330 of file cdr.c.

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

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

01332 {
01333    cdr_object_update_cid(old_snapshot, new_snapshot);
01334    if (old_snapshot->snapshot) {
01335       ao2_t_ref(old_snapshot->snapshot, -1, "Drop ref for swap");
01336    }
01337    ao2_t_ref(new_snapshot, +1, "Bump ref for swap");
01338    old_snapshot->snapshot = new_snapshot;
01339 }

static void cdr_object_transition_state ( struct cdr_object cdr,
struct cdr_object_fn_table fn_table 
) [static]

Transition a cdr_object to a new state.

Parameters:
cdr The cdr_object to transition
fn_table The cdr_object_fn_table state to go to

Definition at line 767 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, CDR_DEBUG, cdr_object::fn_table, cdr_object_fn_table::init_function, cdr_object_fn_table::name, ast_channel_snapshot::name, cdr_object::party_a, RAII_VAR, and cdr_object_snapshot::snapshot.

Referenced by ast_cdr_fork(), bridge_candidate_add_to_cdr(), bridge_state_process_bridge_leave(), bridge_state_process_party_b(), cdr_object_alloc(), cdr_object_check_party_a_hangup(), cdr_object_dispatch_all_cb(), dial_state_process_bridge_enter(), dial_state_process_dial_end(), dial_state_process_party_b(), dialed_pending_state_process_bridge_enter(), dialed_pending_state_process_dial_begin(), dialed_pending_state_process_parking_bridge_enter(), dialed_pending_state_process_party_a(), handle_parking_bridge_enter_message(), parked_state_process_bridge_leave(), single_state_process_bridge_enter(), single_state_process_dial_begin(), and single_state_process_parking_bridge_enter().

00768 {
00769    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
00770 
00771    CDR_DEBUG(mod_cfg, "%p - Transitioning CDR for %s from state %s to %s\n",
00772       cdr, cdr->party_a.snapshot->name,
00773       cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
00774    cdr->fn_table = fn_table;
00775    if (cdr->fn_table->init_function) {
00776       cdr->fn_table->init_function(cdr);
00777    }
00778 }

static void cdr_object_update_cid ( struct cdr_object_snapshot old_snapshot,
struct ast_channel_snapshot new_snapshot 
) [static]

Definition at line 1305 of file cdr.c.

References ast_channel_snapshot::caller_dnid, ast_channel_snapshot::caller_subaddr, ast_channel_snapshot::dialed_subaddr, set_variable(), cdr_object_snapshot::snapshot, and cdr_object_snapshot::variables.

Referenced by cdr_object_swap_snapshot().

01306 {
01307    if (!old_snapshot->snapshot) {
01308       set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
01309       set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
01310       set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
01311       return;
01312    }
01313    if (!strcmp(old_snapshot->snapshot->caller_dnid, new_snapshot->caller_dnid)) {
01314       set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
01315    }
01316    if (!strcmp(old_snapshot->snapshot->caller_subaddr, new_snapshot->caller_subaddr)) {
01317       set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
01318    }
01319    if (!strcmp(old_snapshot->snapshot->dialed_subaddr, new_snapshot->dialed_subaddr)) {
01320       set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
01321    }
01322 }

static int cdr_object_update_party_b ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 2008 of file cdr.c.

References cdr_object::fn_table, ast_channel_snapshot::name, cdr_object::next, cdr_object::party_b, cdr_object_fn_table::process_party_b, and cdr_object_snapshot::snapshot.

Referenced by handle_channel_cache_message().

02009 {
02010    struct cdr_object *cdr = obj;
02011    struct ast_channel_snapshot *party_b = arg;
02012    struct cdr_object *it_cdr;
02013    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
02014       if (!it_cdr->fn_table->process_party_b) {
02015          continue;
02016       }
02017       if (it_cdr->party_b.snapshot
02018          && !strcasecmp(it_cdr->party_b.snapshot->name, party_b->name)) {
02019          it_cdr->fn_table->process_party_b(it_cdr, party_b);
02020       }
02021    }
02022    return 0;
02023 }

static int cdr_object_update_party_b_userfield_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

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

Definition at line 3200 of file cdr.c.

References party_b_userfield_update::channel_name, finalized_state_fn_table, cdr_object::fn_table, ast_channel_snapshot::name, cdr_object::next, cdr_object::party_b, cdr_object_snapshot::snapshot, party_b_userfield_update::userfield, and cdr_object_snapshot::userfield.

Referenced by ast_cdr_setuserfield().

03201 {
03202    struct cdr_object *cdr = obj;
03203    struct party_b_userfield_update *info = arg;
03204    struct cdr_object *it_cdr;
03205    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
03206       if (it_cdr->fn_table == &finalized_state_fn_table) {
03207          continue;
03208       }
03209       if (it_cdr->party_b.snapshot
03210          && !strcasecmp(it_cdr->party_b.snapshot->name, info->channel_name)) {
03211          strcpy(it_cdr->party_b.userfield, info->userfield);
03212       }
03213    }
03214    return 0;
03215 }

static void cdr_submit_batch ( int  shutdown  )  [static]

Definition at line 3480 of file cdr.c.

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, cdr_batch_lock, do_batch_backend_process(), cdr_batch::head, LOG_WARNING, NULL, RAII_VAR, and reset_batch().

Referenced by ast_cdr_engine_term(), and submit_scheduled_batch().

03481 {
03482    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
03483    struct cdr_batch_item *oldbatchitems = NULL;
03484    pthread_t batch_post_thread = AST_PTHREADT_NULL;
03485 
03486    /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
03487    if (!batch || !batch->head) {
03488       return;
03489    }
03490 
03491    /* move the old CDRs aside, and prepare a new CDR batch */
03492    ast_mutex_lock(&cdr_batch_lock);
03493    oldbatchitems = batch->head;
03494    reset_batch();
03495    ast_mutex_unlock(&cdr_batch_lock);
03496 
03497    /* if configured, spawn a new thread to post these CDRs,
03498       also try to save as much as possible if we are shutting down safely */
03499    if (ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SCHEDULER_ONLY) || do_shutdown) {
03500       ast_debug(1, "CDR single-threaded batch processing begins now\n");
03501       do_batch_backend_process(oldbatchitems);
03502    } else {
03503       if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
03504          ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
03505          do_batch_backend_process(oldbatchitems);
03506       } else {
03507          ast_debug(1, "CDR multi-threaded batch processing begins now\n");
03508       }
03509    }
03510 }

static int cdr_toggle_runtime_options ( void   )  [static]

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

Definition at line 4142 of file cdr.c.

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(), LOG_NOTICE, and RAII_VAR.

Referenced by ast_cdr_engine_init(), ast_cdr_engine_reload(), and ast_cdr_set_config().

04143 {
04144    RAII_VAR(struct module_config *, mod_cfg,
04145       ao2_global_obj_ref(module_configs), ao2_cleanup);
04146 
04147    if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
04148       if (create_subscriptions()) {
04149          destroy_subscriptions();
04150          ast_log(AST_LOG_ERROR, "Failed to create Stasis subscriptions\n");
04151          return -1;
04152       }
04153       if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
04154          cdr_enable_batch_mode(mod_cfg->general);
04155       } else {
04156          ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
04157       }
04158    } else {
04159       destroy_subscriptions();
04160       ast_log(LOG_NOTICE, "CDR logging disabled.\n");
04161    }
04162 
04163    return 0;
04164 }

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

References ao2_cleanup, ao2_global_obj_ref, ast_channel_snapshot::appl, AST_SOFTHANGUP_HANGUP_EXEC, ast_strlen_zero, ast_test_flag, CDR_END_BEFORE_H_EXTEN, RAII_VAR, snapshot_cep_changed(), and ast_channel_snapshot::softhangup_flags.

Referenced by handle_channel_cache_message().

02028 {
02029    RAII_VAR(struct module_config *, mod_cfg,
02030          ao2_global_obj_ref(module_configs), ao2_cleanup);
02031 
02032    /* If we're dead, we don't need a new CDR */
02033    if (!new_snapshot
02034       || (ast_test_flag(&new_snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
02035          && ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN))) {
02036       return 0;
02037    }
02038 
02039    /* Auto-fall through will increment the priority but have no application */
02040    if (ast_strlen_zero(new_snapshot->appl)) {
02041       return 0;
02042    }
02043 
02044    if (old_snapshot && !snapshot_cep_changed(old_snapshot, new_snapshot)) {
02045       return 0;
02046    }
02047 
02048    return 1;
02049 }

static char* cli_complete_show ( struct ast_cli_args a  )  [static]

Complete user input for 'cdr show'.

Definition at line 3664 of file cdr.c.

References active_cdrs_by_channel, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_strdup, ast_cli_args::n, ast_channel_snapshot::name, NULL, cdr_object::party_a, result, cdr_object_snapshot::snapshot, and ast_cli_args::word.

Referenced by handle_cli_show().

03665 {
03666    char *result = NULL;
03667    int wordlen = strlen(a->word);
03668    int which = 0;
03669    struct ao2_iterator it_cdrs;
03670    struct cdr_object *cdr;
03671 
03672    it_cdrs = ao2_iterator_init(active_cdrs_by_channel, 0);
03673    while ((cdr = ao2_iterator_next(&it_cdrs))) {
03674       if (!strncasecmp(a->word, cdr->party_a.snapshot->name, wordlen) &&
03675          (++which > a->n)) {
03676          result = ast_strdup(cdr->party_a.snapshot->name);
03677          if (result) {
03678             ao2_ref(cdr, -1);
03679             break;
03680          }
03681       }
03682       ao2_ref(cdr, -1);
03683    }
03684    ao2_iterator_destroy(&it_cdrs);
03685    return result;
03686 }

static void cli_show_channel ( struct ast_cli_args a  )  [static]

Definition at line 3752 of file cdr.c.

References ast_channel_snapshot::accountcode, cdr_object::answer, ao2_cleanup, ao2_lock, ao2_unlock, cdr_object::appl, ast_cli_args::argv, ast_callerid_merge(), ast_cli(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_channel_snapshot::caller_name, ast_channel_snapshot::caller_number, cdr_get_tv(), cdr_object_get_by_name(), cdr_object::data, cdr_object::end, ast_cli_args::fd, FORMAT_STRING, ast_channel_snapshot::name, cdr_object::next, NULL, cdr_object::party_a, cdr_object::party_b, RAII_VAR, cdr_object_snapshot::snapshot, snapshot_is_dialed(), cdr_object::start, and TITLE_STRING.

Referenced by handle_cli_show().

03753 {
03754    struct cdr_object *it_cdr;
03755    char clid[64];
03756    char start_time_buffer[64];
03757    char answer_time_buffer[64];
03758    char end_time_buffer[64];
03759    const char *channel_name = a->argv[3];
03760    RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
03761 
03762 #define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
03763 #define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
03764 
03765    cdr = cdr_object_get_by_name(channel_name);
03766    if (!cdr) {
03767       ast_cli(a->fd, "Unknown channel: %s\n", channel_name);
03768       return;
03769    }
03770 
03771    ast_cli(a->fd, "\n");
03772    ast_cli(a->fd, "Call Detail Record (CDR) Information for %s\n", channel_name);
03773    ast_cli(a->fd, "--------------------------------------------------\n");
03774    ast_cli(a->fd, TITLE_STRING, "AccountCode", "CallerID", "Dst. Channel", "LastApp", "Data", "Start", "Answer", "End", "Billsec", "Duration");
03775 
03776    ao2_lock(cdr);
03777    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
03778       struct timeval end;
03779       if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
03780          continue;
03781       }
03782       ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller_name, it_cdr->party_a.snapshot->caller_number, "");
03783       if (ast_tvzero(it_cdr->end)) {
03784          end = ast_tvnow();
03785       } else {
03786          end = it_cdr->end;
03787       }
03788       cdr_get_tv(it_cdr->start, "%T", start_time_buffer, sizeof(start_time_buffer));
03789       cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
03790       cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
03791       ast_cli(a->fd, FORMAT_STRING,
03792             it_cdr->party_a.snapshot->accountcode,
03793             clid,
03794             it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
03795             it_cdr->appl,
03796             it_cdr->data,
03797             start_time_buffer,
03798             answer_time_buffer,
03799             end_time_buffer,
03800             (long)ast_tvdiff_ms(end, it_cdr->answer) / 1000,
03801             (long)ast_tvdiff_ms(end, it_cdr->start) / 1000);
03802    }
03803    ao2_unlock(cdr);
03804 #undef FORMAT_STRING
03805 #undef TITLE_STRING
03806 }

static void cli_show_channels ( struct ast_cli_args a  )  [static]

Definition at line 3688 of file cdr.c.

References active_cdrs_by_channel, 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(), cdr_get_tv(), cdr_object::end, ast_cli_args::fd, FORMAT_STRING, cdr_object::last, lock, ast_channel_snapshot::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().

03689 {
03690    struct ao2_iterator it_cdrs;
03691    struct cdr_object *cdr;
03692    char start_time_buffer[64];
03693    char answer_time_buffer[64];
03694    char end_time_buffer[64];
03695 
03696 #define TITLE_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
03697 #define FORMAT_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
03698 
03699    ast_cli(a->fd, "\n");
03700    ast_cli(a->fd, "Channels with Call Detail Record (CDR) Information\n");
03701    ast_cli(a->fd, "--------------------------------------------------\n");
03702    ast_cli(a->fd, TITLE_STRING, "Channel", "Dst. Channel", "LastApp", "Start", "Answer", "End", "Billsec", "Duration");
03703 
03704    it_cdrs = ao2_iterator_init(active_cdrs_by_channel, 0);
03705    for (; (cdr = ao2_iterator_next(&it_cdrs)); ao2_cleanup(cdr)) {
03706       struct cdr_object *it_cdr;
03707       struct timeval start_time = { 0, };
03708       struct timeval answer_time = { 0, };
03709       struct timeval end_time = { 0, };
03710 
03711       SCOPED_AO2LOCK(lock, cdr);
03712 
03713       /* Calculate the start, end, answer, billsec, and duration over the
03714        * life of all of the CDR entries
03715        */
03716       for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
03717          if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
03718             continue;
03719          }
03720          if (ast_tvzero(start_time)) {
03721             start_time = it_cdr->start;
03722          }
03723          if (!ast_tvzero(it_cdr->answer) && ast_tvzero(answer_time)) {
03724             answer_time = it_cdr->answer;
03725          }
03726       }
03727 
03728       /* If there was no start time, then all CDRs were for a dialed channel; skip */
03729       if (ast_tvzero(start_time)) {
03730          continue;
03731       }
03732       it_cdr = cdr->last;
03733 
03734       end_time = ast_tvzero(it_cdr->end) ? ast_tvnow() : it_cdr->end;
03735       cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
03736       cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
03737       cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
03738       ast_cli(a->fd, FORMAT_STRING, it_cdr->party_a.snapshot->name,
03739             it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
03740             it_cdr->appl,
03741             start_time_buffer,
03742             answer_time_buffer,
03743             end_time_buffer,
03744             ast_tvzero(answer_time) ? 0 : (long)ast_tvdiff_ms(end_time, answer_time) / 1000,
03745             (long)ast_tvdiff_ms(end_time, start_time) / 1000);
03746    }
03747    ao2_iterator_destroy(&it_cdrs);
03748 #undef FORMAT_STRING
03749 #undef TITLE_STRING
03750 }

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

static int copy_variables ( struct varshead to_list,
struct varshead from_list 
) [static]

Copy variables from one list to another.

Parameters:
to_list destination
from_list source
Return values:
The number of copied variables

Definition at line 705 of file cdr.c.

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

00706 {
00707    struct ast_var_t *variables;
00708    struct ast_var_t *newvariable;
00709    const char *var;
00710    const char *val;
00711    int x = 0;
00712 
00713    AST_LIST_TRAVERSE(from_list, variables, entries) {
00714       var = ast_var_name(variables);
00715       if (ast_strlen_zero(var)) {
00716          continue;
00717       }
00718       val = ast_var_value(variables);
00719       if (ast_strlen_zero(val)) {
00720          continue;
00721       }
00722       newvariable = ast_var_assign(var, val);
00723       if (newvariable) {
00724          AST_LIST_INSERT_HEAD(to_list, newvariable, entries);
00725          ++x;
00726       }
00727    }
00728 
00729    return x;
00730 }

static int create_subscriptions ( void   )  [static]

Create the Stasis subcriptions for CDRs.

Definition at line 3997 of file cdr.c.

References ast_bridge_topic_all_cached(), ast_channel_topic_all_cached(), ast_parking_topic(), bridge_subscription, cdr_topic, channel_subscription, parking_subscription, and stasis_forward_all().

Referenced by ast_cel_engine_init(), and cdr_toggle_runtime_options().

03998 {
03999    if (!cdr_topic) {
04000       return -1;
04001    }
04002 
04003    if (channel_subscription || bridge_subscription || parking_subscription) {
04004       return 0;
04005    }
04006 
04007    channel_subscription = stasis_forward_all(ast_channel_topic_all_cached(), cdr_topic);
04008    if (!channel_subscription) {
04009       return -1;
04010    }
04011    bridge_subscription = stasis_forward_all(ast_bridge_topic_all_cached(), cdr_topic);
04012    if (!bridge_subscription) {
04013       return -1;
04014    }
04015    parking_subscription = stasis_forward_all(ast_parking_topic(), cdr_topic);
04016    if (!parking_subscription) {
04017       return -1;
04018    }
04019 
04020    return 0;
04021 }

static void destroy_subscriptions ( void   )  [static]

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

References active_cdrs_by_channel, ao2_cleanup, ao2_container_count(), ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_string_field_set, cdr_object::bridge, BRIDGE_ENTER_NO_PARTY_B, BRIDGE_ENTER_OBTAINED_PARTY_B, BRIDGE_ENTER_ONLY_PARTY, bridge_state_fn_table, cdr_object_finalize(), cdr_object_snapshot_copy(), cdr_object_transition_state(), ast_bridge_snapshot::channels, cdr_object::fn_table, ast_channel_snapshot::name, cdr_object::next, OBJ_KEY, cdr_object::party_a, cdr_object::party_b, RAII_VAR, cdr_object_snapshot::snapshot, and ast_bridge_snapshot::uniqueid.

01684 {
01685    struct ao2_iterator it_cdrs;
01686    char *channel_id;
01687    int success = 0;
01688 
01689    ast_string_field_set(cdr, bridge, bridge->uniqueid);
01690 
01691    /* Get parties in the bridge */
01692    if (ao2_container_count(bridge->channels) == 1) {
01693       /* No one in the bridge yet but us! */
01694       cdr_object_transition_state(cdr, &bridge_state_fn_table);
01695       return BRIDGE_ENTER_ONLY_PARTY;
01696    }
01697 
01698    for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
01699       !success && (channel_id = ao2_iterator_next(&it_cdrs));
01700       ao2_ref(channel_id, -1)) {
01701       RAII_VAR(struct cdr_object *, cand_cdr_master,
01702          ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
01703          ao2_cleanup);
01704       struct cdr_object *cand_cdr;
01705 
01706       if (!cand_cdr_master) {
01707          continue;
01708       }
01709 
01710       ao2_lock(cand_cdr_master);
01711       for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
01712          /* Skip any records that are not in a bridge or in this bridge.
01713           * I'm not sure how that would happen, but it pays to be careful. */
01714          if (cand_cdr->fn_table != &bridge_state_fn_table ||
01715                strcmp(cdr->bridge, cand_cdr->bridge)) {
01716             continue;
01717          }
01718 
01719          /* If we don't have a Party B (originated channel), skip it */
01720          if (!cdr->party_b.snapshot) {
01721             continue;
01722          }
01723 
01724          /* Skip any records that aren't our Party B */
01725          if (strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name)) {
01726             continue;
01727          }
01728          cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
01729          /* If they have a Party B, they joined up with someone else as their
01730           * Party A. Don't finalize them as they're active. Otherwise, we
01731           * have stolen them so they need to be finalized.
01732           */
01733          if (!cand_cdr->party_b.snapshot) {
01734             cdr_object_finalize(cand_cdr);
01735          }
01736          success = 1;
01737          break;
01738       }
01739       ao2_unlock(cand_cdr_master);
01740    }
01741    ao2_iterator_destroy(&it_cdrs);
01742 
01743    /* We always transition state, even if we didn't get a peer */
01744    cdr_object_transition_state(cdr, &bridge_state_fn_table);
01745 
01746    /* Success implies that we have a Party B */
01747    if (success) {
01748       return BRIDGE_ENTER_OBTAINED_PARTY_B;
01749    }
01750    return BRIDGE_ENTER_NO_PARTY_B;
01751 }

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

01617 {
01618    /* Don't process a begin dial here. A party A already in the dial state will
01619     * who receives a dial begin for something else will be handled by the
01620     * message router callback and will add a new CDR for the party A */
01621    return 1;
01622 }

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

References ast_assert, AST_CDR_ANSWERED, 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::name, cdr_object::party_a, cdr_object::party_b, and cdr_object_snapshot::snapshot.

01652 {
01653    struct ast_channel_snapshot *party_a;
01654 
01655    if (caller) {
01656       party_a = caller;
01657    } else {
01658       party_a = peer;
01659    }
01660    ast_assert(!strcasecmp(cdr->party_a.snapshot->name, party_a->name));
01661    cdr_object_swap_snapshot(&cdr->party_a, party_a);
01662 
01663    if (cdr->party_b.snapshot) {
01664       if (strcasecmp(cdr->party_b.snapshot->name, peer->name)) {
01665          /* Not the status for this CDR - defer back to the message router */
01666          return 1;
01667       }
01668       cdr_object_swap_snapshot(&cdr->party_b, peer);
01669    }
01670 
01671    /* Set the disposition based on the dial string. */
01672    cdr->disposition = dial_status_to_disposition(dial_status);
01673    if (cdr->disposition == AST_CDR_ANSWERED) {
01674       /* Switch to dial pending to wait and see what the caller does */
01675       cdr_object_transition_state(cdr, &dialed_pending_state_fn_table);
01676    } else {
01677       cdr_object_transition_state(cdr, &finalized_state_fn_table);
01678    }
01679 
01680    return 0;
01681 }

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

Definition at line 1600 of file cdr.c.

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

01601 {
01602    ast_assert(snapshot != NULL);
01603 
01604    if (!cdr->party_b.snapshot
01605       || strcasecmp(cdr->party_b.snapshot->name, snapshot->name)) {
01606       return;
01607    }
01608    cdr_object_swap_snapshot(&cdr->party_b, snapshot);
01609 
01610    /* If party B hangs up, finalize this CDR */
01611    if (ast_test_flag(&cdr->party_b.snapshot->flags, AST_FLAG_DEAD)) {
01612       cdr_object_transition_state(cdr, &finalized_state_fn_table);
01613    }
01614 }

static enum ast_cdr_disposition dial_status_to_disposition ( const char *  dial_status  )  [static]

Definition at line 1628 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_CONGESTION, AST_CDR_FAILED, AST_CDR_NOANSWER, ast_test_flag, CDR_CONGESTION, and RAII_VAR.

Referenced by dial_state_process_dial_end().

01629 {
01630    RAII_VAR(struct module_config *, mod_cfg,
01631       ao2_global_obj_ref(module_configs), ao2_cleanup);
01632 
01633    if (!strcmp(dial_status, "ANSWER")) {
01634       return AST_CDR_ANSWERED;
01635    } else if (!strcmp(dial_status, "BUSY")) {
01636       return AST_CDR_BUSY;
01637    } else if (!strcmp(dial_status, "CANCEL") || !strcmp(dial_status, "NOANSWER")) {
01638       return AST_CDR_NOANSWER;
01639    } else if (!strcmp(dial_status, "CONGESTION")) {
01640       if (!ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION)) {
01641          return AST_CDR_FAILED;
01642       } else {
01643          return AST_CDR_CONGESTION;
01644       }
01645    } else if (!strcmp(dial_status, "FAILED")) {
01646       return AST_CDR_FAILED;
01647    }
01648    return AST_CDR_FAILED;
01649 }

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

Definition at line 1775 of file cdr.c.

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

01776 {
01777    cdr_object_transition_state(cdr, &dial_state_fn_table);
01778    return cdr->fn_table->process_bridge_enter(cdr, bridge, channel);
01779 }

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

Definition at line 1791 of file cdr.c.

References cdr_object_transition_state(), and finalized_state_fn_table.

01792 {
01793    cdr_object_transition_state(cdr, &finalized_state_fn_table);
01794 
01795    /* Ask for a new CDR */
01796    return 1;
01797 }

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

Definition at line 1781 of file cdr.c.

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

01782 {
01783    if (cdr->party_b.snapshot) {
01784       /* We can't handle this as we have a Party B - ask for a new one */
01785       return 1;
01786    }
01787    cdr_object_transition_state(cdr, &parked_state_fn_table);
01788    return 0;
01789 }

static int dialed_pending_state_process_party_a ( struct cdr_object cdr,
struct ast_channel_snapshot snapshot 
) [static]

Definition at line 1755 of file cdr.c.

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

01756 {
01757    /* If we get a CEP change, we're executing dialplan. If we have a Party B
01758     * that means we need a new CDR; otherwise, switch us over to single.
01759     */
01760    if (snapshot_cep_changed(cdr->party_a.snapshot, snapshot)) {
01761       if (cdr->party_b.snapshot) {
01762          cdr_object_transition_state(cdr, &finalized_state_fn_table);
01763          cdr->fn_table->process_party_a(cdr, snapshot);
01764          return 1;
01765       } else {
01766          cdr_object_transition_state(cdr, &single_state_fn_table);
01767          cdr->fn_table->process_party_a(cdr, snapshot);
01768          return 0;
01769       }
01770    }
01771    base_process_party_a(cdr, snapshot);
01772    return 0;
01773 }

static void* do_batch_backend_process ( void *  data  )  [static]

Definition at line 3463 of file cdr.c.

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

Referenced by cdr_submit_batch().

03464 {
03465    struct cdr_batch_item *processeditem;
03466    struct cdr_batch_item *batchitem = data;
03467 
03468    /* Push each CDR into storage mechanism(s) and free all the memory */
03469    while (batchitem) {
03470       post_cdr(batchitem->cdr);
03471       ast_cdr_free(batchitem->cdr);
03472       processeditem = batchitem;
03473       batchitem = batchitem->next;
03474       ast_free(processeditem);
03475    }
03476 
03477    return NULL;
03478 }

static void* do_cdr ( void *  data  )  [static]

Definition at line 3604 of file cdr.c.

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

Referenced by cdr_enable_batch_mode().

03605 {
03606    struct timespec timeout;
03607    int schedms;
03608    int numevents = 0;
03609 
03610    for (;;) {
03611       struct timeval now;
03612       schedms = ast_sched_wait(sched);
03613       /* this shouldn't happen, but provide a 1 second default just in case */
03614       if (schedms <= 0)
03615          schedms = 1000;
03616       now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
03617       timeout.tv_sec = now.tv_sec;
03618       timeout.tv_nsec = now.tv_usec * 1000;
03619       /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
03620       ast_mutex_lock(&cdr_pending_lock);
03621       ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
03622       numevents = ast_sched_runq(sched);
03623       ast_mutex_unlock(&cdr_pending_lock);
03624       ast_debug(2, "Processed %d scheduled CDR batches from the run queue\n", numevents);
03625    }
03626 
03627    return NULL;
03628 }

static int filter_bridge_messages ( struct ast_bridge_snapshot bridge  )  [static]

Filter bridge messages based on bridge technology.

Definition at line 2170 of file cdr.c.

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

Referenced by handle_bridge_enter_message(), and handle_bridge_leave_message().

02171 {
02172    /* Ignore holding bridge technology messages. We treat this simply as an application
02173     * that a channel enters into.
02174     */
02175    if (!strcmp(bridge->technology, "holding_bridge") && strcmp(bridge->subclass, "parking")) {
02176       return 1;
02177    }
02178    return 0;
02179 }

static int filter_channel_cache_message ( struct ast_channel_snapshot old_snapshot,
struct ast_channel_snapshot new_snapshot 
) [static]

Definition at line 1876 of file cdr.c.

References filter_channel_snapshot().

Referenced by handle_channel_cache_message().

01878 {
01879    int ret = 0;
01880 
01881    /* Drop cache updates from certain channel technologies */
01882    if (old_snapshot) {
01883       ret |= filter_channel_snapshot(old_snapshot);
01884    }
01885    if (new_snapshot) {
01886       ret |= filter_channel_snapshot(new_snapshot);
01887    }
01888 
01889    return ret;
01890 }

static int filter_channel_snapshot ( struct ast_channel_snapshot snapshot  )  [static]

static void finalize_batch_mode ( void   )  [static]

Definition at line 3960 of file cdr.c.

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

Referenced by ast_cdr_engine_reload(), and cdr_engine_shutdown().

03961 {
03962    if (cdr_thread == AST_PTHREADT_NULL) {
03963       return;
03964    }
03965    /* wake up the thread so it will exit */
03966    pthread_cancel(cdr_thread);
03967    pthread_kill(cdr_thread, SIGURG);
03968    pthread_join(cdr_thread, NULL);
03969    cdr_thread = AST_PTHREADT_NULL;
03970    ast_cond_destroy(&cdr_pending_cond);
03971    ast_cdr_engine_term();
03972 }

static void finalized_state_init_function ( struct cdr_object cdr  )  [static]

Definition at line 1844 of file cdr.c.

References cdr_object_finalize().

01845 {
01846    cdr_object_finalize(cdr);
01847 }

static int finalized_state_process_party_a ( struct cdr_object cdr,
struct ast_channel_snapshot snapshot 
) [static]

Definition at line 1849 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, AST_SOFTHANGUP_HANGUP_EXEC, ast_test_flag, CDR_END_BEFORE_H_EXTEN, RAII_VAR, and ast_channel_snapshot::softhangup_flags.

01850 {
01851    RAII_VAR(struct module_config *, mod_cfg,
01852       ao2_global_obj_ref(module_configs), ao2_cleanup);
01853 
01854    if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
01855          && ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)) {
01856       return 0;
01857    }
01858 
01859    /* Indicate that, if possible, we should get a new CDR */
01860    return 1;
01861 }

static void free_variables ( struct varshead headp  )  [static]

Delete all variables from a variable list.

Parameters:
headp The head pointer to the variable list to delete

Definition at line 736 of file cdr.c.

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

Referenced by ast_cdr_fork(), and ast_cdr_free().

00737 {
00738    struct ast_var_t *vardata;
00739 
00740    while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
00741       ast_var_delete(vardata);
00742    }
00743 }

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

Definition at line 2493 of file cdr.c.

References active_cdrs_by_channel, ao2_cleanup, ao2_find, ao2_global_obj_ref, ast_assert, ast_log, AST_LOG_WARNING, ast_bridge_blob::bridge, CDR_DEBUG, ast_bridge_blob::channel, filter_bridge_messages(), filter_channel_snapshot(), handle_parking_bridge_enter_message(), handle_standard_bridge_enter_message(), ast_channel_snapshot::name, OBJ_KEY, RAII_VAR, stasis_message_data(), stasis_message_timestamp(), ast_bridge_snapshot::subclass, ast_channel_snapshot::uniqueid, and update().

Referenced by ast_cdr_engine_init().

02495 {
02496    struct ast_bridge_blob *update = stasis_message_data(message);
02497    struct ast_bridge_snapshot *bridge = update->bridge;
02498    struct ast_channel_snapshot *channel = update->channel;
02499    RAII_VAR(struct cdr_object *, cdr,
02500          ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY),
02501          ao2_cleanup);
02502    RAII_VAR(struct module_config *, mod_cfg,
02503          ao2_global_obj_ref(module_configs), ao2_cleanup);
02504 
02505    if (filter_bridge_messages(bridge)) {
02506       return;
02507    }
02508 
02509    if (filter_channel_snapshot(channel)) {
02510       return;
02511    }
02512 
02513    CDR_DEBUG(mod_cfg, "Bridge Enter message for channel %s: %u.%08u\n",
02514          channel->name,
02515          (unsigned int)stasis_message_timestamp(message)->tv_sec,
02516          (unsigned int)stasis_message_timestamp(message)->tv_usec);
02517 
02518    if (!cdr) {
02519       ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
02520       ast_assert(0);
02521       return;
02522    }
02523 
02524    if (!strcmp(bridge->subclass, "parking")) {
02525       handle_parking_bridge_enter_message(cdr, bridge, channel);
02526    } else {
02527       handle_standard_bridge_enter_message(cdr, bridge, channel);
02528    }
02529 }

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

Handler for when a channel leaves a bridge.

Parameters:
data Passed on
sub The stasis subscription for this message callback
topic The topic this message was published for
message The message - hopefully a bridge one!

Definition at line 2188 of file cdr.c.

References active_cdrs_by_channel, ao2_callback, ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_lock, ao2_unlock, ast_assert, ast_log, AST_LOG_WARNING, ast_string_field_set, bridge_leave_data::bridge, ast_bridge_blob::bridge, CDR_DEBUG, cdr_object_party_b_left_bridge_cb(), ast_bridge_blob::channel, filter_bridge_messages(), filter_channel_snapshot(), cdr_object::fn_table, ast_channel_snapshot::name, cdr_object::next, OBJ_KEY, OBJ_NODATA, cdr_object_fn_table::process_bridge_leave, RAII_VAR, stasis_message_data(), stasis_message_timestamp(), ast_bridge_snapshot::subclass, ast_channel_snapshot::uniqueid, and update().

Referenced by ast_cdr_engine_init().

02190 {
02191    struct ast_bridge_blob *update = stasis_message_data(message);
02192    struct ast_bridge_snapshot *bridge = update->bridge;
02193    struct ast_channel_snapshot *channel = update->channel;
02194    RAII_VAR(struct module_config *, mod_cfg,
02195          ao2_global_obj_ref(module_configs), ao2_cleanup);
02196    RAII_VAR(struct cdr_object *, cdr,
02197          ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY),
02198          ao2_cleanup);
02199    struct cdr_object *it_cdr;
02200    struct bridge_leave_data leave_data = {
02201       .bridge = bridge,
02202       .channel = channel,
02203    };
02204    int left_bridge = 0;
02205 
02206    if (filter_bridge_messages(bridge)) {
02207       return;
02208    }
02209 
02210    if (filter_channel_snapshot(channel)) {
02211       return;
02212    }
02213 
02214    CDR_DEBUG(mod_cfg, "Bridge Leave message for %s: %u.%08u\n",
02215          channel->name,
02216          (unsigned int)stasis_message_timestamp(message)->tv_sec,
02217          (unsigned int)stasis_message_timestamp(message)->tv_usec);
02218 
02219    if (!cdr) {
02220       ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
02221       ast_assert(0);
02222       return;
02223    }
02224 
02225    /* Party A */
02226    ao2_lock(cdr);
02227    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
02228       if (!it_cdr->fn_table->process_bridge_leave) {
02229          continue;
02230       }
02231       CDR_DEBUG(mod_cfg, "%p - Processing Bridge Leave for %s\n",
02232             it_cdr, channel->name);
02233       if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
02234          ast_string_field_set(it_cdr, bridge, "");
02235          left_bridge = 1;
02236       }
02237    }
02238    ao2_unlock(cdr);
02239    if (!left_bridge) {
02240       return;
02241    }
02242 
02243    if (strcmp(bridge->subclass, "parking")) {
02244       /* Party B */
02245       ao2_callback(active_cdrs_by_channel, OBJ_NODATA,
02246             cdr_object_party_b_left_bridge_cb,
02247             &leave_data);
02248    }
02249 }

static void handle_bridge_pairings ( struct cdr_object cdr,
struct ast_bridge_snapshot bridge 
) [static]

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

Parameters:
cdr The cdr_object that just entered the bridge
bridge The ast_bridge_snapshot representing the bridge it just entered

Definition at line 2346 of file cdr.c.

References active_cdrs_by_channel, ao2_cleanup, ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, bridge_candidate_process(), ast_bridge_snapshot::channels, OBJ_KEY, and RAII_VAR.

Referenced by handle_standard_bridge_enter_message().

02347 {
02348    struct ao2_iterator it_channels;
02349    char *channel_id;
02350 
02351    it_channels = ao2_iterator_init(bridge->channels, 0);
02352    while ((channel_id = ao2_iterator_next(&it_channels))) {
02353       RAII_VAR(struct cdr_object *, cand_cdr,
02354          ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
02355          ao2_cleanup);
02356 
02357       if (!cand_cdr) {
02358          ao2_ref(channel_id, -1);
02359          continue;
02360       }
02361 
02362       bridge_candidate_process(cdr, cand_cdr);
02363 
02364       ao2_ref(channel_id, -1);
02365    }
02366    ao2_iterator_destroy(&it_channels);
02367 }

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

Handler for a synchronization message.

Parameters:
data Passed on
sub The stasis subscription for this message callback
topic The topic this message was published for
message A blank ao2 object

Definition at line 2605 of file cdr.c.

Referenced by ast_cdr_engine_init().

02607 {
02608    return;
02609 }

static void handle_channel_cache_message ( void *  data,
struct stasis_subscription sub,
struct stasis_message message 
) [static]

Handler for Stasis-Core channel cache update messages.

Parameters:
data Passed on
sub The stasis subscription for this message callback
topic The topic this message was published for
message The message

Definition at line 2058 of file cdr.c.

References active_cdrs_by_channel, ao2_callback, ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_link, ao2_lock, ao2_unlink, ao2_unlock, ast_assert, ast_channel_snapshot_type(), ast_log, AST_LOG_WARNING, CDR_DEBUG, cdr_object_alloc(), cdr_object_create_and_append(), cdr_object_dispatch(), cdr_object_finalize(), cdr_object_finalize_party_b(), cdr_object_update_party_b(), check_new_cdr_needed(), filter_channel_cache_message(), cdr_object::fn_table, ast_channel_snapshot::name, cdr_beitem::name, stasis_cache_update::new_snapshot, cdr_object::next, NULL, OBJ_KEY, OBJ_NODATA, stasis_cache_update::old_snapshot, cdr_object_fn_table::process_party_a, RAII_VAR, stasis_message_data(), stasis_cache_update::type, ast_channel_snapshot::uniqueid, and update().

Referenced by ast_cdr_engine_init().

02059 {
02060    RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
02061    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
02062    struct stasis_cache_update *update = stasis_message_data(message);
02063    struct ast_channel_snapshot *old_snapshot;
02064    struct ast_channel_snapshot *new_snapshot;
02065    const char *uniqueid;
02066    const char *name;
02067    struct cdr_object *it_cdr;
02068 
02069    ast_assert(update != NULL);
02070    ast_assert(ast_channel_snapshot_type() == update->type);
02071 
02072    old_snapshot = stasis_message_data(update->old_snapshot);
02073    new_snapshot = stasis_message_data(update->new_snapshot);
02074    uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid;
02075    name = new_snapshot ? new_snapshot->name : old_snapshot->name;
02076 
02077    if (filter_channel_cache_message(old_snapshot, new_snapshot)) {
02078       return;
02079    }
02080 
02081    if (new_snapshot && !old_snapshot) {
02082       cdr = cdr_object_alloc(new_snapshot);
02083       if (!cdr) {
02084          return;
02085       }
02086       ao2_link(active_cdrs_by_channel, cdr);
02087    }
02088 
02089    /* Handle Party A */
02090    if (!cdr) {
02091       cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_KEY);
02092    }
02093    if (!cdr) {
02094       ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name);
02095       ast_assert(0);
02096    } else {
02097       ao2_lock(cdr);
02098       if (new_snapshot) {
02099          int all_reject = 1;
02100          for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
02101             if (!it_cdr->fn_table->process_party_a) {
02102                continue;
02103             }
02104             all_reject &= it_cdr->fn_table->process_party_a(it_cdr, new_snapshot);
02105          }
02106          if (all_reject && check_new_cdr_needed(old_snapshot, new_snapshot)) {
02107             /* We're not hung up and we have a new snapshot - we need a new CDR */
02108             struct cdr_object *new_cdr;
02109             new_cdr = cdr_object_create_and_append(cdr);
02110             if (new_cdr) {
02111                new_cdr->fn_table->process_party_a(new_cdr, new_snapshot);
02112             }
02113          }
02114       } else {
02115          CDR_DEBUG(mod_cfg, "%p - Beginning finalize/dispatch for %s\n", cdr, old_snapshot->name);
02116          for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
02117             cdr_object_finalize(it_cdr);
02118          }
02119          cdr_object_dispatch(cdr);
02120          ao2_unlink(active_cdrs_by_channel, cdr);
02121       }
02122       ao2_unlock(cdr);
02123    }
02124 
02125    /* Handle Party B */
02126    if (new_snapshot) {
02127       ao2_callback(active_cdrs_by_channel, OBJ_NODATA, cdr_object_update_party_b,
02128          new_snapshot);
02129    } else {
02130       ao2_callback(active_cdrs_by_channel, OBJ_NODATA, cdr_object_finalize_party_b,
02131          old_snapshot);
02132    }
02133 
02134 }

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

Definition at line 3630 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ast_cli_args::argc, ast_cli_args::argv, ast_clear_flag, ast_cli(), ast_set_flag, ast_test_flag, CDR_DEBUG, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, NULL, RAII_VAR, and ast_cli_entry::usage.

03631 {
03632    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
03633 
03634    switch (cmd) {
03635    case CLI_INIT:
03636       e->command = "cdr set debug [on|off]";
03637       e->usage = "Enable or disable extra debugging in the CDR Engine. Note\n"
03638             "that this will dump debug information to the VERBOSE setting\n"
03639             "and should only be used when debugging information from the\n"
03640             "CDR engine is needed.\n";
03641       return NULL;
03642    case CLI_GENERATE:
03643       return NULL;
03644    }
03645 
03646    if (a->argc != 4) {
03647       return CLI_SHOWUSAGE;
03648    }
03649 
03650    if (!strcasecmp(a->argv[3], "on")
03651       && !ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
03652       ast_set_flag(&mod_cfg->general->settings, CDR_DEBUG);
03653       ast_cli(a->fd, "CDR debugging enabled\n");
03654    } else if (!strcasecmp(a->argv[3], "off")
03655       && ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
03656       ast_clear_flag(&mod_cfg->general->settings, CDR_DEBUG);
03657       ast_cli(a->fd, "CDR debugging disabled\n");
03658    }
03659 
03660    return CLI_SUCCESS;
03661 }

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

Definition at line 3808 of file cdr.c.

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

03809 {
03810    switch (cmd) {
03811    case CLI_INIT:
03812          e->command = "cdr show active";
03813          e->usage =
03814             "Usage: cdr show active [channel]\n"
03815             "  Displays a summary of all Call Detail Records when [channel]\n"
03816             "  is omitted; displays all of the Call Detail Records\n"
03817             "  currently in flight for a given [channel] when [channel] is\n"
03818             "  specified.\n\n"
03819             "  Note that this will not display Call Detail Records that\n"
03820             "  have already been dispatched to a backend storage, nor for\n"
03821             "  channels that are no longer active.\n";
03822          return NULL;
03823    case CLI_GENERATE:
03824       return cli_complete_show(a);
03825    }
03826 
03827    if (a->argc > 4) {
03828       return CLI_SHOWUSAGE;
03829    } else if (a->argc < 4) {
03830       cli_show_channels(a);
03831    } else {
03832       cli_show_channel(a);
03833    }
03834 
03835    return CLI_SUCCESS;
03836 }

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

Definition at line 3838 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ast_cli_args::argc, ast_cli(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_sched_when(), ast_test_flag, batch, BATCH_MODE_SAFE_SHUTDOWN, BATCH_MODE_SCHEDULER_ONLY, CDR_BATCHMODE, CDR_CONGESTION, CDR_ENABLED, cdr_sched, CDR_UNANSWERED, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ESS, ast_cli_args::fd, cdr_beitem::list, cdr_beitem::name, NULL, RAII_VAR, cdr_batch::size, cdr_beitem::suspended, and ast_cli_entry::usage.

03839 {
03840    struct cdr_beitem *beitem = NULL;
03841    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
03842    int cnt = 0;
03843    long nextbatchtime = 0;
03844 
03845    switch (cmd) {
03846    case CLI_INIT:
03847       e->command = "cdr show status";
03848       e->usage =
03849          "Usage: cdr show status\n"
03850          "  Displays the Call Detail Record engine system status.\n";
03851       return NULL;
03852    case CLI_GENERATE:
03853       return NULL;
03854    }
03855 
03856    if (a->argc > 3) {
03857       return CLI_SHOWUSAGE;
03858    }
03859 
03860    ast_cli(a->fd, "\n");
03861    ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
03862    ast_cli(a->fd, "----------------------------------\n");
03863    ast_cli(a->fd, "  Logging:                    %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) ? "Enabled" : "Disabled");
03864    ast_cli(a->fd, "  Mode:                       %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE) ? "Batch" : "Simple");
03865    if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
03866       ast_cli(a->fd, "  Log unanswered calls:       %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) ? "Yes" : "No");
03867       ast_cli(a->fd, "  Log congestion:             %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION) ? "Yes" : "No");
03868       if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
03869          ast_cli(a->fd, "* Batch Mode Settings\n");
03870          ast_cli(a->fd, "  -------------------\n");
03871          if (batch)
03872             cnt = batch->size;
03873          if (cdr_sched > -1)
03874             nextbatchtime = ast_sched_when(sched, cdr_sched);
03875          ast_cli(a->fd, "  Safe shutdown:              %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN) ? "Enabled" : "Disabled");
03876          ast_cli(a->fd, "  Threading model:            %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SCHEDULER_ONLY) ? "Scheduler only" : "Scheduler plus separate threads");
03877          ast_cli(a->fd, "  Current batch size:         %d record%s\n", cnt, ESS(cnt));
03878          ast_cli(a->fd, "  Maximum batch size:         %u record%s\n", mod_cfg->general->batch_settings.size, ESS(mod_cfg->general->batch_settings.size));
03879          ast_cli(a->fd, "  Maximum batch time:         %u second%s\n", mod_cfg->general->batch_settings.time, ESS(mod_cfg->general->batch_settings.time));
03880          ast_cli(a->fd, "  Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
03881       }
03882       ast_cli(a->fd, "* Registered Backends\n");
03883       ast_cli(a->fd, "  -------------------\n");
03884       AST_RWLIST_RDLOCK(&be_list);
03885       if (AST_RWLIST_EMPTY(&be_list)) {
03886          ast_cli(a->fd, "    (none)\n");
03887       } else {
03888          AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
03889             ast_cli(a->fd, "    %s%s\n", beitem->name, beitem->suspended ? " (suspended) " : "");
03890          }
03891       }
03892       AST_RWLIST_UNLOCK(&be_list);
03893       ast_cli(a->fd, "\n");
03894    }
03895 
03896    return CLI_SUCCESS;
03897 }

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

Definition at line 3899 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ast_cli_args::argc, ast_cli(), ast_test_flag, CDR_BATCHMODE, CDR_ENABLED, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, NULL, RAII_VAR, submit_unscheduled_batch(), and ast_cli_entry::usage.

03900 {
03901    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
03902 
03903    switch (cmd) {
03904    case CLI_INIT:
03905       e->command = "cdr submit";
03906       e->usage =
03907          "Usage: cdr submit\n"
03908          "Posts all pending batched CDR data to the configured CDR\n"
03909          "backend engine modules.\n";
03910       return NULL;
03911    case CLI_GENERATE:
03912       return NULL;
03913    }
03914    if (a->argc > 2) {
03915       return CLI_SHOWUSAGE;
03916    }
03917 
03918    if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
03919       ast_cli(a->fd, "Cannot submit CDR batch: CDR engine disabled.\n");
03920       return CLI_SUCCESS;
03921    }
03922 
03923    if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
03924       ast_cli(a->fd, "Cannot submit CDR batch: batch mode not enabled.\n");
03925       return CLI_SUCCESS;
03926    }
03927 
03928    submit_unscheduled_batch();
03929    ast_cli(a->fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
03930 
03931    return CLI_SUCCESS;
03932 }

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

Handler for Stasis-Core dial messages.

Parameters:
data Passed on
sub The stasis subscription for this message callback
topic The topic this message was published for
message The message

Definition at line 1901 of file cdr.c.

References active_cdrs_by_channel, ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_lock, ao2_unlock, ast_assert, ast_json_object_get(), ast_json_string_get(), ast_log, AST_LOG_WARNING, ast_multi_channel_blob_get_channel(), ast_multi_channel_blob_get_json(), ast_strlen_zero, CDR_DEBUG, cdr_object_create_and_append(), filter_channel_snapshot(), cdr_object::fn_table, ast_channel_snapshot::name, cdr_object::next, NULL, OBJ_KEY, cdr_object_fn_table::process_dial_begin, cdr_object_fn_table::process_dial_end, RAII_VAR, stasis_message_data(), stasis_message_timestamp(), and ast_channel_snapshot::uniqueid.

Referenced by ast_cdr_engine_init().

01902 {
01903    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
01904    RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
01905    struct ast_multi_channel_blob *payload = stasis_message_data(message);
01906    struct ast_channel_snapshot *caller;
01907    struct ast_channel_snapshot *peer;
01908    struct cdr_object *it_cdr;
01909    struct ast_json *dial_status_blob;
01910    const char *dial_status = NULL;
01911    int res = 1;
01912 
01913    caller = ast_multi_channel_blob_get_channel(payload, "caller");
01914    peer = ast_multi_channel_blob_get_channel(payload, "peer");
01915    if (!peer && !caller) {
01916       return;
01917    }
01918    dial_status_blob = ast_json_object_get(ast_multi_channel_blob_get_json(payload), "dialstatus");
01919    if (dial_status_blob) {
01920       dial_status = ast_json_string_get(dial_status_blob);
01921    }
01922 
01923    CDR_DEBUG(mod_cfg, "Dial %s message for %s, %s: %u.%08u\n",
01924          ast_strlen_zero(dial_status) ? "Begin" : "End",
01925          caller ? caller->name : "(none)",
01926          peer ? peer->name : "(none)",
01927          (unsigned int)stasis_message_timestamp(message)->tv_sec,
01928          (unsigned int)stasis_message_timestamp(message)->tv_usec);
01929 
01930    if (filter_channel_snapshot(peer) || (caller && filter_channel_snapshot(caller))) {
01931       return;
01932    }
01933 
01934    /* Figure out who is running this show */
01935    if (caller) {
01936       cdr = ao2_find(active_cdrs_by_channel, caller->uniqueid, OBJ_KEY);
01937    } else {
01938       cdr = ao2_find(active_cdrs_by_channel, peer->uniqueid, OBJ_KEY);
01939    }
01940 
01941    if (!cdr) {
01942       ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->name : peer->name);
01943       ast_assert(0);
01944       return;
01945    }
01946 
01947    ao2_lock(cdr);
01948    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
01949       if (ast_strlen_zero(dial_status)) {
01950          if (!it_cdr->fn_table->process_dial_begin) {
01951             continue;
01952          }
01953          CDR_DEBUG(mod_cfg, "%p - Processing Dial Begin message for channel %s, peer %s\n",
01954                it_cdr,
01955                caller ? caller->name : "(none)",
01956                peer ? peer->name : "(none)");
01957          res &= it_cdr->fn_table->process_dial_begin(it_cdr,
01958                caller,
01959                peer);
01960       } else {
01961          if (!it_cdr->fn_table->process_dial_end) {
01962             continue;
01963          }
01964          CDR_DEBUG(mod_cfg, "%p - Processing Dial End message for channel %s, peer %s\n",
01965                it_cdr,
01966                caller ? caller->name : "(none)",
01967                peer ? peer->name : "(none)");
01968          it_cdr->fn_table->process_dial_end(it_cdr,
01969                caller,
01970                peer,
01971                dial_status);
01972       }
01973    }
01974 
01975    /* If no CDR handled a dial begin message, make a new one */
01976    if (res && ast_strlen_zero(dial_status)) {
01977       struct cdr_object *new_cdr;
01978 
01979       new_cdr = cdr_object_create_and_append(cdr);
01980       if (!new_cdr) {
01981          ao2_unlock(cdr);
01982          return;
01983       }
01984       new_cdr->fn_table->process_dial_begin(new_cdr,
01985             caller,
01986             peer);
01987    }
01988    ao2_unlock(cdr);
01989 }

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

Handler for when a channel is parked.

Parameters:
data Passed on
sub The stasis subscription for this message callback
topic The topic this message was published for
message The message about who got parked

Definition at line 2538 of file cdr.c.

References active_cdrs_by_channel, ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_lock, ao2_unlock, ast_assert, ast_log, AST_LOG_WARNING, CDR_DEBUG, cdr_object_create_and_append(), ast_parked_call_payload::event_type, filter_channel_snapshot(), cdr_object::fn_table, ast_channel_snapshot::name, cdr_object::next, NULL, OBJ_KEY, PARKED_CALL, ast_parked_call_payload::parkee, cdr_object_fn_table::process_parked_channel, RAII_VAR, stasis_message_data(), stasis_message_timestamp(), and ast_channel_snapshot::uniqueid.

Referenced by ast_cdr_engine_init().

02540 {
02541    struct ast_parked_call_payload *payload = stasis_message_data(message);
02542    struct ast_channel_snapshot *channel = payload->parkee;
02543    RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
02544    RAII_VAR(struct module_config *, mod_cfg,
02545          ao2_global_obj_ref(module_configs), ao2_cleanup);
02546    int unhandled = 1;
02547    struct cdr_object *it_cdr;
02548 
02549    /* Anything other than getting parked will be handled by other updates */
02550    if (payload->event_type != PARKED_CALL) {
02551       return;
02552    }
02553 
02554    /* No one got parked? */
02555    if (!channel) {
02556       return;
02557    }
02558 
02559    if (filter_channel_snapshot(channel)) {
02560       return;
02561    }
02562 
02563    CDR_DEBUG(mod_cfg, "Parked Call message for channel %s: %u.%08u\n",
02564          channel->name,
02565          (unsigned int)stasis_message_timestamp(message)->tv_sec,
02566          (unsigned int)stasis_message_timestamp(message)->tv_usec);
02567 
02568    cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY);
02569    if (!cdr) {
02570       ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
02571       ast_assert(0);
02572       return;
02573    }
02574 
02575    ao2_lock(cdr);
02576 
02577    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
02578       if (it_cdr->fn_table->process_parked_channel) {
02579          unhandled &= it_cdr->fn_table->process_parked_channel(it_cdr, payload);
02580       }
02581    }
02582 
02583    if (unhandled) {
02584       /* Nothing handled the messgae - we need a new one! */
02585       struct cdr_object *new_cdr = cdr_object_create_and_append(cdr);
02586       if (new_cdr) {
02587          /* As the new CDR is created in the single state, it is guaranteed
02588           * to have a function for the parked call message and will handle
02589           * the message */
02590          new_cdr->fn_table->process_parked_channel(new_cdr, payload);
02591       }
02592    }
02593 
02594    ao2_unlock(cdr);
02595 
02596 }

static void handle_parking_bridge_enter_message ( struct cdr_object cdr,
struct ast_bridge_snapshot bridge,
struct ast_channel_snapshot channel 
) [static]

Handle entering into a parking bridge.

Parameters:
cdr The CDR to operate on
bridge The bridge the channel just entered
channel The channel snapshot

Definition at line 2374 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ao2_lock, ao2_unlock, CDR_DEBUG, cdr_object_create_and_append(), cdr_object_transition_state(), cdr_object::fn_table, ast_channel_snapshot::name, cdr_object::next, cdr_object_fn_table::process_parking_bridge_enter, cdr_object_fn_table::process_party_a, RAII_VAR, and single_state_fn_table.

Referenced by handle_bridge_enter_message().

02377 {
02378    RAII_VAR(struct module_config *, mod_cfg,
02379          ao2_global_obj_ref(module_configs), ao2_cleanup);
02380    int res = 1;
02381    struct cdr_object *it_cdr;
02382    struct cdr_object *new_cdr;
02383 
02384    ao2_lock(cdr);
02385 
02386    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
02387       if (it_cdr->fn_table->process_parking_bridge_enter) {
02388          res &= it_cdr->fn_table->process_parking_bridge_enter(it_cdr, bridge, channel);
02389       }
02390       if (it_cdr->fn_table->process_party_a) {
02391          CDR_DEBUG(mod_cfg, "%p - Updating Party A %s snapshot\n", it_cdr,
02392                channel->name);
02393          it_cdr->fn_table->process_party_a(it_cdr, channel);
02394       }
02395    }
02396 
02397    if (res) {
02398       /* No one handled it - we need a new one! */
02399       new_cdr = cdr_object_create_and_append(cdr);
02400       if (new_cdr) {
02401          /* Let the single state transition us to Parked */
02402          cdr_object_transition_state(new_cdr, &single_state_fn_table);
02403          new_cdr->fn_table->process_parking_bridge_enter(new_cdr, bridge, channel);
02404       }
02405    }
02406    ao2_unlock(cdr);
02407 }

static void handle_standard_bridge_enter_message ( struct cdr_object cdr,
struct ast_bridge_snapshot bridge,
struct ast_channel_snapshot channel 
) [static]

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

Parameters:
cdr The CDR to operate on
bridge The bridge the channel just entered
channel The channel snapshot

Definition at line 2414 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ao2_lock, ao2_unlock, BRIDGE_ENTER_NEED_CDR, BRIDGE_ENTER_NO_PARTY_B, BRIDGE_ENTER_OBTAINED_PARTY_B, BRIDGE_ENTER_ONLY_PARTY, CDR_DEBUG, cdr_object_create_and_append(), cdr_object_finalize(), cdr_object::fn_table, handle_bridge_pairings(), ast_channel_snapshot::name, cdr_object::next, NULL, cdr_object_fn_table::process_bridge_enter, cdr_object_fn_table::process_party_a, RAII_VAR, and result.

Referenced by handle_bridge_enter_message().

02417 {
02418    RAII_VAR(struct module_config *, mod_cfg,
02419          ao2_global_obj_ref(module_configs), ao2_cleanup);
02420    enum process_bridge_enter_results result;
02421    struct cdr_object *it_cdr;
02422    struct cdr_object *new_cdr;
02423    struct cdr_object *handled_cdr = NULL;
02424 
02425    ao2_lock(cdr);
02426 
02427    for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
02428       if (it_cdr->fn_table->process_party_a) {
02429          CDR_DEBUG(mod_cfg, "%p - Updating Party A %s snapshot\n", it_cdr,
02430                channel->name);
02431          it_cdr->fn_table->process_party_a(it_cdr, channel);
02432       }
02433 
02434       /* Notify all states that they have entered a bridge */
02435       if (it_cdr->fn_table->process_bridge_enter) {
02436          CDR_DEBUG(mod_cfg, "%p - Processing bridge enter for %s\n", it_cdr,
02437                channel->name);
02438          result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
02439          switch (result) {
02440          case BRIDGE_ENTER_ONLY_PARTY:
02441             /* Fall through */
02442          case BRIDGE_ENTER_OBTAINED_PARTY_B:
02443             if (!handled_cdr) {
02444                handled_cdr = it_cdr;
02445             }
02446             break;
02447          case BRIDGE_ENTER_NEED_CDR:
02448             /* Pass */
02449             break;
02450          case BRIDGE_ENTER_NO_PARTY_B:
02451             /* We didn't win on any - end this CDR. If someone else comes in later
02452              * that is Party B to this CDR, it can re-activate this CDR.
02453              */
02454             if (!handled_cdr) {
02455                handled_cdr = it_cdr;
02456             }
02457             cdr_object_finalize(cdr);
02458             break;
02459          }
02460       }
02461    }
02462 
02463    /* Create the new matchings, but only for either:
02464     *  * The first CDR in the chain that handled it. This avoids issues with
02465     *    forked CDRs.
02466     *  * If no one handled it, the last CDR in the chain. This would occur if
02467     *    a CDR joined a bridge and it wasn't Party A for anyone. We still need
02468     *    to make pairings with everyone in the bridge.
02469     */
02470    if (handled_cdr) {
02471       handle_bridge_pairings(handled_cdr, bridge);
02472    } else {
02473       /* Nothing handled it - we need a new one! */
02474       new_cdr = cdr_object_create_and_append(cdr);
02475       if (new_cdr) {
02476          /* This is guaranteed to succeed: the new CDR is created in the single state
02477           * and will be able to handle the bridge enter message
02478           */
02479          handle_standard_bridge_enter_message(cdr, bridge, channel);
02480       }
02481    }
02482    ao2_unlock(cdr);
02483 }

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 3452 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by cdr_detach().

03453 {
03454    /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
03455    if (!(batch = ast_malloc(sizeof(*batch))))
03456       return -1;
03457 
03458    reset_batch();
03459 
03460    return 0;
03461 }

static void * module_config_alloc ( void   )  [static]

Create a new module config object.

Definition at line 268 of file cdr.c.

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

Referenced by process_config().

00269 {
00270    struct module_config *mod_cfg;
00271    struct ast_cdr_config *cdr_config;
00272 
00273    mod_cfg = ao2_alloc(sizeof(*mod_cfg), module_config_destructor);
00274    if (!mod_cfg) {
00275       return NULL;
00276    }
00277 
00278    cdr_config = ao2_alloc(sizeof(*cdr_config), NULL);
00279    if (!cdr_config) {
00280       ao2_ref(cdr_config, -1);
00281       return NULL;
00282    }
00283    mod_cfg->general = cdr_config;
00284 
00285    return mod_cfg;
00286 }

static void module_config_destructor ( void *  obj  )  [static]

Dispose of a module config object.

Definition at line 257 of file cdr.c.

References ao2_ref, and module_config::general.

Referenced by module_config_alloc().

00258 {
00259    struct module_config *cfg = obj;
00260 
00261    if (!cfg) {
00262       return;
00263    }
00264    ao2_ref(cfg->general, -1);
00265 }

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

Definition at line 1832 of file cdr.c.

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

01833 {
01834    if (strcasecmp(cdr->party_a.snapshot->name, channel->name)) {
01835       return 1;
01836    }
01837    cdr_object_transition_state(cdr, &finalized_state_fn_table);
01838 
01839    return 0;
01840 }

static void post_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 3245 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, AST_CDR_ANSWERED, AST_CDR_FLAG_DISABLE, ast_debug, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strlen_zero, ast_test_flag, cdr_beitem::be, CDR_UNANSWERED, ast_cdr::channel, ast_cdr::disposition, ast_cdr::dstchannel, cdr_beitem::list, ast_cdr::next, RAII_VAR, and cdr_beitem::suspended.

Referenced by cdr_detach(), and do_batch_backend_process().

03246 {
03247    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
03248    struct cdr_beitem *i;
03249 
03250    for (; cdr ; cdr = cdr->next) {
03251       /* For people, who don't want to see unanswered single-channel events */
03252       if (!ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) &&
03253             cdr->disposition < AST_CDR_ANSWERED &&
03254             (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
03255          ast_debug(1, "Skipping CDR  for %s since we weren't answered\n", cdr->channel);
03256          continue;
03257       }
03258 
03259       if (ast_test_flag(cdr, AST_CDR_FLAG_DISABLE)) {
03260          continue;
03261       }
03262       AST_RWLIST_RDLOCK(&be_list);
03263       AST_RWLIST_TRAVERSE(&be_list, i, list) {
03264          if (!i->suspended) {
03265             i->be(cdr);
03266          }
03267       }
03268       AST_RWLIST_UNLOCK(&be_list);
03269    }
03270 }

static int process_config ( int  reload  )  [static]

Definition at line 4023 of file cdr.c.

References ACO_EXACT, aco_info_init(), aco_option_register, aco_process_config(), aco_set_defaults(), ao2_cleanup, ao2_global_obj_replace_unref, ast_log, BATCH_MODE_SAFE_SHUTDOWN, BATCH_MODE_SCHEDULER_ONLY, CDR_BATCHMODE, CDR_CONGESTION, CDR_DEBUG, CDR_ENABLED, CDR_END_BEFORE_H_EXTEN, CDR_INITIATED_SECONDS, CDR_UNANSWERED, DEFAULT_BATCH_SAFE_SHUTDOWN, DEFAULT_BATCH_SCHEDULER_ONLY, DEFAULT_BATCH_SIZE, DEFAULT_BATCH_TIME, DEFAULT_BATCHMODE, DEFAULT_ENABLED, DEFAULT_END_BEFORE_H_EXTEN, DEFAULT_INITIATED_SECONDS, DEFAULT_UNANSWERED, FLDSET, LOG_NOTICE, MAX_BATCH_SIZE, MAX_BATCH_TIME, module_config_alloc(), OPT_BOOLFLAG_T, OPT_UINT_T, PARSE_IN_RANGE, RAII_VAR, and settings.

Referenced by ast_ari_config_init(), ast_ari_config_reload(), ast_cdr_engine_init(), and ast_cdr_engine_reload().

04024 {
04025    RAII_VAR(struct module_config *, mod_cfg, module_config_alloc(), ao2_cleanup);
04026 
04027    if (!reload) {
04028       if (aco_info_init(&cfg_info)) {
04029          return 1;
04030       }
04031 
04032       aco_option_register(&cfg_info, "enable", ACO_EXACT, general_options, DEFAULT_ENABLED, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_ENABLED);
04033       aco_option_register(&cfg_info, "debug", ACO_EXACT, general_options, 0, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_DEBUG);
04034       aco_option_register(&cfg_info, "unanswered", ACO_EXACT, general_options, DEFAULT_UNANSWERED, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_UNANSWERED);
04035       aco_option_register(&cfg_info, "congestion", ACO_EXACT, general_options, 0, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_CONGESTION);
04036       aco_option_register(&cfg_info, "batch", ACO_EXACT, general_options, DEFAULT_BATCHMODE, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_BATCHMODE);
04037       aco_option_register(&cfg_info, "endbeforehexten", ACO_EXACT, general_options, DEFAULT_END_BEFORE_H_EXTEN, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_END_BEFORE_H_EXTEN);
04038       aco_option_register(&cfg_info, "initiatedseconds", ACO_EXACT, general_options, DEFAULT_INITIATED_SECONDS, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_INITIATED_SECONDS);
04039       aco_option_register(&cfg_info, "scheduleronly", ACO_EXACT, general_options, DEFAULT_BATCH_SCHEDULER_ONLY, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, batch_settings.settings), BATCH_MODE_SCHEDULER_ONLY);
04040       aco_option_register(&cfg_info, "safeshutdown", ACO_EXACT, general_options, DEFAULT_BATCH_SAFE_SHUTDOWN, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, batch_settings.settings), BATCH_MODE_SAFE_SHUTDOWN);
04041       aco_option_register(&cfg_info, "size", ACO_EXACT, general_options, DEFAULT_BATCH_SIZE, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_cdr_config, batch_settings.size), 0, MAX_BATCH_SIZE);
04042       aco_option_register(&cfg_info, "time", ACO_EXACT, general_options, DEFAULT_BATCH_TIME, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_cdr_config, batch_settings.time), 0, MAX_BATCH_TIME);
04043    }
04044 
04045    if (aco_process_config(&cfg_info, reload)) {
04046       if (!mod_cfg) {
04047          return 1;
04048       }
04049       /* If we couldn't process the configuration and this wasn't a reload,
04050        * create a default config
04051        */
04052       if (!reload && !(aco_set_defaults(&general_option, "general", mod_cfg->general))) {
04053          ast_log(LOG_NOTICE, "Failed to process CDR configuration; using defaults\n");
04054          ao2_global_obj_replace_unref(module_configs, mod_cfg);
04055          return 0;
04056       }
04057       return 1;
04058    }
04059 
04060    return 0;
04061 }

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 3444 of file cdr.c.

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

Referenced by cdr_submit_batch(), and init_batch().

03445 {
03446    batch->size = 0;
03447    batch->head = NULL;
03448    batch->tail = NULL;
03449 }

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

Definition at line 1055 of file cdr.c.

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

Referenced by ast_cdr_setvar(), and cdr_object_update_cid().

01056 {
01057    struct ast_var_t *newvariable;
01058 
01059    AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
01060       if (!strcasecmp(ast_var_name(newvariable), name)) {
01061          AST_LIST_REMOVE_CURRENT(entries);
01062          ast_var_delete(newvariable);
01063          break;
01064       }
01065    }
01066    AST_LIST_TRAVERSE_SAFE_END;
01067 
01068    if (value && (newvariable = ast_var_assign(name, value))) {
01069       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
01070    }
01071 }

static int single_state_bridge_enter_comparison ( struct cdr_object cdr,
struct cdr_object cand_cdr 
) [static]

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

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

Definition at line 1491 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, CDR_DEBUG, cdr_object_finalize(), cdr_object_pick_party_a(), cdr_object_snapshot_copy(), ast_channel_snapshot::name, cdr_object::party_a, cdr_object::party_b, RAII_VAR, and cdr_object_snapshot::snapshot.

Referenced by single_state_process_bridge_enter().

01493 {
01494    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
01495    struct cdr_object_snapshot *party_a;
01496 
01497    /* Don't match on ourselves */
01498    if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)) {
01499       return 1;
01500    }
01501 
01502    /* Try the candidate CDR's Party A first */
01503    party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
01504    if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
01505       CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
01506          cdr, cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name);
01507       cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
01508       if (!cand_cdr->party_b.snapshot) {
01509          /* We just stole them - finalize their CDR. Note that this won't
01510           * transition their state, it just sets the end time and the
01511           * disposition - if we need to re-activate them later, we can.
01512           */
01513          cdr_object_finalize(cand_cdr);
01514       }
01515       return 0;
01516    }
01517 
01518    /* Try their Party B, unless it's us */
01519    if (!cand_cdr->party_b.snapshot
01520       || !strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name)) {
01521       return 1;
01522    }
01523    party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b);
01524    if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
01525       CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
01526          cdr, cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name);
01527       cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
01528       return 0;
01529    }
01530 
01531    return 1;
01532 }

static void single_state_init_function ( struct cdr_object cdr  )  [static]

Definition at line 1438 of file cdr.c.

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

01438                                                                {
01439    cdr->start = ast_tvnow();
01440    cdr_object_check_party_a_answer(cdr);
01441 }

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

Definition at line 1534 of file cdr.c.

References active_cdrs_by_channel, ao2_cleanup, ao2_container_count(), ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_string_field_set, cdr_object::bridge, BRIDGE_ENTER_NO_PARTY_B, BRIDGE_ENTER_OBTAINED_PARTY_B, BRIDGE_ENTER_ONLY_PARTY, bridge_state_fn_table, cdr_object_transition_state(), ast_bridge_snapshot::channels, cdr_object::fn_table, cdr_object::next, OBJ_KEY, RAII_VAR, single_state_bridge_enter_comparison(), and ast_bridge_snapshot::uniqueid.

01535 {
01536    struct ao2_iterator it_cdrs;
01537    char *channel_id;
01538    int success = 0;
01539 
01540    ast_string_field_set(cdr, bridge, bridge->uniqueid);
01541 
01542    if (ao2_container_count(bridge->channels) == 1) {
01543       /* No one in the bridge yet but us! */
01544       cdr_object_transition_state(cdr, &bridge_state_fn_table);
01545       return BRIDGE_ENTER_ONLY_PARTY;
01546    }
01547 
01548    for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
01549       !success && (channel_id = ao2_iterator_next(&it_cdrs));
01550       ao2_ref(channel_id, -1)) {
01551       RAII_VAR(struct cdr_object *, cand_cdr_master,
01552          ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
01553          ao2_cleanup);
01554       struct cdr_object *cand_cdr;
01555 
01556       if (!cand_cdr_master) {
01557          continue;
01558       }
01559 
01560       ao2_lock(cand_cdr_master);
01561       for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
01562          /* Skip any records that are not in a bridge or in this bridge.
01563           * I'm not sure how that would happen, but it pays to be careful. */
01564          if (cand_cdr->fn_table != &bridge_state_fn_table ||
01565                strcmp(cdr->bridge, cand_cdr->bridge)) {
01566             continue;
01567          }
01568 
01569          if (single_state_bridge_enter_comparison(cdr, cand_cdr)) {
01570             continue;
01571          }
01572          /* We successfully got a party B - break out */
01573          success = 1;
01574          break;
01575       }
01576       ao2_unlock(cand_cdr_master);
01577    }
01578    ao2_iterator_destroy(&it_cdrs);
01579 
01580    /* We always transition state, even if we didn't get a peer */
01581    cdr_object_transition_state(cdr, &bridge_state_fn_table);
01582 
01583    /* Success implies that we have a Party B */
01584    if (success) {
01585       return BRIDGE_ENTER_OBTAINED_PARTY_B;
01586    }
01587 
01588    return BRIDGE_ENTER_NO_PARTY_B;
01589 }

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

Definition at line 1451 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, AST_CDR_LOCK_APP, ast_set_flag, base_process_party_a(), CDR_DEBUG, cdr_object_swap_snapshot(), cdr_object_transition_state(), dial_state_fn_table, cdr_object::flags, ast_channel_snapshot::name, cdr_object::party_a, cdr_object::party_b, RAII_VAR, and cdr_object_snapshot::snapshot.

01452 {
01453    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
01454 
01455    if (caller && !strcasecmp(cdr->party_a.snapshot->name, caller->name)) {
01456       base_process_party_a(cdr, caller);
01457       CDR_DEBUG(mod_cfg, "%p - Updated Party A %s snapshot\n", cdr,
01458             cdr->party_a.snapshot->name);
01459       cdr_object_swap_snapshot(&cdr->party_b, peer);
01460       CDR_DEBUG(mod_cfg, "%p - Updated Party B %s snapshot\n", cdr,
01461             cdr->party_b.snapshot->name);
01462 
01463       /* If we have two parties, lock the application that caused the
01464        * two parties to be associated. This prevents mid-call event
01465        * macros/gosubs from perturbing the CDR application/data
01466        */
01467       ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
01468    } else if (!strcasecmp(cdr->party_a.snapshot->name, peer->name)) {
01469       /* We're the entity being dialed, i.e., outbound origination */
01470       base_process_party_a(cdr, peer);
01471       CDR_DEBUG(mod_cfg, "%p - Updated Party A %s snapshot\n", cdr,
01472             cdr->party_a.snapshot->name);
01473    }
01474 
01475    cdr_object_transition_state(cdr, &dial_state_fn_table);
01476    return 0;
01477 }

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

Definition at line 1591 of file cdr.c.

References cdr_object_transition_state(), and parked_state_fn_table.

01592 {
01593    cdr_object_transition_state(cdr, &parked_state_fn_table);
01594    return 0;
01595 }

static void single_state_process_party_b ( struct cdr_object cdr,
struct ast_channel_snapshot snapshot 
) [static]

Definition at line 1443 of file cdr.c.

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

01444 {
01445    /* This should never happen! */
01446    ast_assert(cdr->party_b.snapshot == NULL);
01447    ast_assert(0);
01448    return;
01449 }

static int snapshot_cep_changed ( struct ast_channel_snapshot old_snapshot,
struct ast_channel_snapshot new_snapshot 
) [static]

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

Parameters:
old_snapshot The previous state
new_snapshot The new state
Return values:
0 if the state has not changed
1 if the state changed

Definition at line 939 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ast_channel_snapshot::appl, AST_SOFTHANGUP_HANGUP_EXEC, ast_test_flag, CDR_END_BEFORE_H_EXTEN, ast_channel_snapshot::context, ast_channel_snapshot::exten, ast_channel_snapshot::priority, RAII_VAR, and ast_channel_snapshot::softhangup_flags.

Referenced by check_new_cdr_needed(), and dialed_pending_state_process_party_a().

00941 {
00942    RAII_VAR(struct module_config *, mod_cfg,
00943       ao2_global_obj_ref(module_configs), ao2_cleanup);
00944 
00945    /* If we ignore hangup logic, don't indicate that we're executing anything new */
00946    if (ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)
00947       && ast_test_flag(&new_snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) {
00948       return 0;
00949    }
00950 
00951    /* When Party A is originated to an application and the application exits, the stack
00952     * will attempt to clear the application and restore the dummy originate application
00953     * of "AppDialX". Ignore application changes to AppDialX as a result.
00954     */
00955    if (strcmp(new_snapshot->appl, old_snapshot->appl) && strncasecmp(new_snapshot->appl, "appdial", 7)
00956       && (strcmp(new_snapshot->context, old_snapshot->context)
00957       || strcmp(new_snapshot->exten, old_snapshot->exten)
00958       || new_snapshot->priority != old_snapshot->priority)) {
00959       return 1;
00960    }
00961 
00962    return 0;
00963 }

static int snapshot_is_dialed ( struct ast_channel_snapshot snapshot  )  [static]

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

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

Definition at line 972 of file cdr.c.

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

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

00973 {
00974    return (ast_test_flag(&snapshot->flags, AST_FLAG_OUTGOING)
00975          && !(ast_test_flag(&snapshot->flags, AST_FLAG_ORIGINATED)));
00976 }

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( cdr_sync_message_type   ) 

A message type used to synchronize with the CDR topic.

static int submit_scheduled_batch ( const void *  data  )  [static]

Definition at line 3512 of file cdr.c.

References ao2_cleanup, ao2_global_obj_ref, ast_mutex_lock, ast_mutex_unlock, ast_sched_add(), cdr_sched, cdr_sched_lock, cdr_submit_batch(), NULL, and RAII_VAR.

Referenced by cdr_enable_batch_mode(), and submit_unscheduled_batch().

03513 {
03514    RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
03515    cdr_submit_batch(0);
03516    /* manually reschedule from this point in time */
03517 
03518    ast_mutex_lock(&cdr_sched_lock);
03519    cdr_sched = ast_sched_add(sched, mod_cfg->general->batch_settings.time * 1000, submit_scheduled_batch, NULL);
03520    ast_mutex_unlock(&cdr_sched_lock);
03521    /* returning zero so the scheduler does not automatically reschedule */
03522    return 0;
03523 }

static void submit_unscheduled_batch ( void   )  [static]

Do not hold the batch lock while calling this function

Definition at line 3526 of file cdr.c.

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

Referenced by cdr_detach(), and handle_cli_submit().

03527 {
03528    /* Prevent two deletes from happening at the same time */
03529    ast_mutex_lock(&cdr_sched_lock);
03530    /* this is okay since we are not being called from within the scheduler */
03531    AST_SCHED_DEL(sched, cdr_sched);
03532    /* schedule the submission to occur ASAP (1 ms) */
03533    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
03534    ast_mutex_unlock(&cdr_sched_lock);
03535 
03536    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
03537    ast_mutex_lock(&cdr_pending_lock);
03538    ast_cond_signal(&cdr_pending_cond);
03539    ast_mutex_unlock(&cdr_pending_lock);
03540 }


Variable Documentation

struct cdr_batch * batch [static]

The virtual table for the Bridged state.

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

A cdr_object from this state can go to: * finalized_state_fn_table

Definition at line 621 of file cdr.c.

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

Our subscription for bridges.

Definition at line 336 of file cdr.c.

Referenced by create_subscriptions(), and destroy_subscriptions().

ast_mutex_t cdr_batch_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Lock protecting modifications to the batch queue.

Definition at line 323 of file cdr.c.

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

ast_mutex_t cdr_pending_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

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

Definition at line 326 of file cdr.c.

Referenced by do_cdr(), and submit_unscheduled_batch().

const char* const cdr_readonly_vars[] [static]

Definition at line 2896 of file cdr.c.

Referenced by ast_cdr_serialize_variables(), and ast_cdr_setvar().

int cdr_sched = -1 [static]

ast_mutex_t cdr_sched_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 319 of file cdr.c.

Referenced by submit_scheduled_batch(), and submit_unscheduled_batch().

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 320 of file cdr.c.

Referenced by cdr_enable_batch_mode(), and finalize_batch_mode().

struct stasis_topic* cdr_topic [static]

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

Definition at line 345 of file cdr.c.

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

Our subscription for channels.

Definition at line 339 of file cdr.c.

Referenced by create_subscriptions(), and destroy_subscriptions().

struct ast_cli_entry cli_commands[] [static]

Definition at line 3934 of file cdr.c.

Referenced by ast_cdr_engine_init(), cdr_engine_shutdown(), load_module(), and unload_pjsip().

The virtual table for the Dial state.

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

A cdr_object from this state can go in any of the following states: * dialed_pending_state_fn_table * bridge_state_fn_table * finalized_state_fn_table

Definition at line 566 of file cdr.c.

Referenced by dialed_pending_state_process_bridge_enter(), and single_state_process_dial_begin().

The virtual table for the Dialed Pending state.

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

A cdr_object from this state can go in any of the following states: * single_state_fn_table * dialed_pending_state_fn_table * bridge_state_fn_table * finalized_state_fn_table

Definition at line 599 of file cdr.c.

Referenced by dial_state_process_dial_end().

struct aco_type general_option [static]

The type definition for general options.

Definition at line 232 of file cdr.c.

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

Definition at line 254 of file cdr.c.

Referenced by get_general_options(), and set_general_options().

int global_cdr_sequence = 0 [static]

The global sequence counter used for CDRs.

Definition at line 314 of file cdr.c.

Referenced by cdr_object_alloc().

struct aco_file module_file_conf [static]

Initial value:

 {
   .filename = "cdr.conf",
   .skip_category = "(^csv$|^custom$|^manager$|^odbc$|^pgsql$|^radius$|^sqlite$|^tds$|^mysql$)",
   .types = ACO_TYPES(&general_option),
}
The file definition.

Definition at line 244 of file cdr.c.

The virtual table for the Parked state.

Parking is weird. Unlike typical bridges, it has to be treated somewhat uniquely - a channel in a parking b