Fri Nov 12 11:54:13 2010

Asterisk developer's documentation


cdr.c File Reference

Call Detail Record API. More...

#include "asterisk.h"
#include <signal.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 dependency graph for cdr.c:

Go to the source code of this file.

Data Structures

struct  ast_cdr_batch
struct  ast_cdr_batch_item
struct  ast_cdr_beitem
struct  be_list

Defines

#define BATCH_SAFE_SHUTDOWN_DEFAULT   1
#define BATCH_SCHEDULER_ONLY_DEFAULT   0
#define BATCH_SIZE_DEFAULT   100
#define BATCH_TIME_DEFAULT   300

Functions

struct ast_cdrast_cdr_alloc (void)
 Allocate a CDR record.
int ast_cdr_amaflags2int (const char *flag)
 Convert a string to a detail record AMA flag.
void ast_cdr_answer (struct ast_cdr *cdr)
 Answer a call.
struct ast_cdrast_cdr_append (struct ast_cdr *cdr, struct ast_cdr *newcdr)
int ast_cdr_appenduserfield (struct ast_channel *chan, const char *userfield)
 Append to CDR user field for channel (stored in CDR).
void ast_cdr_busy (struct ast_cdr *cdr)
 Busy a call.
int ast_cdr_copy_vars (struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
void ast_cdr_detach (struct ast_cdr *cdr)
 Detaches the detail record for posting (and freeing) either now or at a later time in bulk with other records during batch mode operation.
void ast_cdr_discard (struct ast_cdr *cdr)
 the same as a cdr_free call, only with no checks; just get rid of it
char * ast_cdr_disp2str (int disposition)
 Disposition to a string.
int ast_cdr_disposition (struct ast_cdr *cdr, int cause)
 Save the result of the call based on the AST_CAUSE_*.
struct ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a record.
void ast_cdr_end (struct ast_cdr *cdr)
 End a call.
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)
void ast_cdr_failed (struct ast_cdr *cdr)
 Fail a call.
char * ast_cdr_flags2str (int flag)
void ast_cdr_free (struct ast_cdr *cdr)
 Free a CDR record.
void ast_cdr_free_vars (struct ast_cdr *cdr, int recur)
void ast_cdr_getvar (struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw)
static const char * ast_cdr_getvar_internal (struct ast_cdr *cdr, const char *name, int recur)
int ast_cdr_init (struct ast_cdr *cdr, struct ast_channel *c)
 Initialize based on a channel.
int ast_cdr_isset_unanswered (void)
void ast_cdr_merge (struct ast_cdr *to, struct ast_cdr *from)
 Move the non-null data from the "from" cdr to the "to" cdr.
void ast_cdr_noanswer (struct ast_cdr *cdr)
 A call wasn't answered.
int ast_cdr_register (const char *name, const char *desc, ast_cdrbe be)
 Register a CDR handling engine.
void ast_cdr_reset (struct ast_cdr *cdr, struct ast_flags *_flags)
 Reset the detail record, optionally posting it first.
int ast_cdr_serialize_variables (struct ast_cdr *cdr, struct ast_str **buf, char delim, char sep, int recur)
int ast_cdr_setaccount (struct ast_channel *chan, const char *account)
 Set account code, will generate AMI event.
int ast_cdr_setamaflags (struct ast_channel *chan, const char *flag)
 Set AMA flags for channel.
void ast_cdr_setanswer (struct ast_cdr *cdr, struct timeval t)
 Set the answer time for a call.
void ast_cdr_setapp (struct ast_cdr *cdr, const char *app, const char *data)
 Set the last executed application.
int ast_cdr_setcid (struct ast_cdr *cdr, struct ast_channel *c)
 Initialize based on a channel.
void ast_cdr_setdestchan (struct ast_cdr *cdr, const char *chann)
 Set the destination channel, if there was one.
void ast_cdr_setdisposition (struct ast_cdr *cdr, long int disposition)
 Set the disposition for a call.
int ast_cdr_setuserfield (struct ast_channel *chan, const char *userfield)
 Set CDR user field for channel (stored in CDR).
int ast_cdr_setvar (struct ast_cdr *cdr, const char *name, const char *value, int recur)
void ast_cdr_specialized_reset (struct ast_cdr *cdr, struct ast_flags *_flags)
void ast_cdr_start (struct ast_cdr *cdr)
 Start a call.
void ast_cdr_submit_batch (int do_shutdown)
 Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines.
void ast_cdr_unregister (const char *name)
 Unregister a CDR handling engine.
int ast_cdr_update (struct ast_channel *c)
static void cdr_get_tv (struct timeval when, const char *fmt, char *buf, int bufsize)
static void cdr_merge_vars (struct ast_cdr *to, struct ast_cdr *from)
int check_cdr_enabled ()
 Return TRUE if CDR subsystem is enabled.
static void check_post (struct ast_cdr *cdr)
 print a warning if cdr already posted
static void * do_batch_backend_process (void *data)
static void * do_cdr (void *data)
static int do_reload (int reload)
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 int init_batch (void)
static void post_cdr (struct ast_cdr *cdr)
static void reset_batch (void)
static void set_one_cid (struct ast_cdr *cdr, struct ast_channel *c)
static int submit_scheduled_batch (const void *data)
static void submit_unscheduled_batch (void)

Variables

char ast_default_accountcode [AST_MAX_ACCOUNT_CODE]
int ast_default_amaflags = AST_CDR_DOCUMENTATION
static struct ast_cdr_batchbatch
static int batchmode
static int batchsafeshutdown
static int batchscheduleronly
static int batchsize
static int batchtime
static ast_mutex_t cdr_batch_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
static ast_cond_t cdr_pending_cond
static ast_mutex_t cdr_pending_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
static const char * cdr_readonly_vars []
static int cdr_sched = -1
static pthread_t cdr_thread = AST_PTHREADT_NULL
static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CDR status")
static struct ast_cli_entry cli_submit = AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data")
static int enabled
static struct sched_contextsched
static int unanswered

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 BATCH_SAFE_SHUTDOWN_DEFAULT   1

Definition at line 84 of file cdr.c.

Referenced by do_reload().

#define BATCH_SCHEDULER_ONLY_DEFAULT   0

Definition at line 83 of file cdr.c.

Referenced by do_reload().

#define BATCH_SIZE_DEFAULT   100

Definition at line 81 of file cdr.c.

Referenced by do_reload().

#define BATCH_TIME_DEFAULT   300

Definition at line 82 of file cdr.c.

Referenced by do_reload().


Function Documentation

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

References ast_calloc, ast_log(), and LOG_ERROR.

Referenced by __agent_start_monitoring(), __ast_channel_alloc_ap(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_dup(), builtin_blindtransfer(), clear_caller(), findmeexec(), and start_monitor_exec().

00453 {
00454    struct ast_cdr *x;
00455    x = ast_calloc(1, sizeof(*x));
00456    if (!x)
00457       ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
00458    return x;
00459 }

int ast_cdr_amaflags2int ( const char *  flag  ) 

Convert a string to a detail record AMA flag.

Parameters:
flag string form of flag Converts the string form of the flag to the binary form.
Returns:
the binary form of the flag

Definition at line 1016 of file cdr.c.

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

Referenced by ast_cdr_setamaflags(), build_device(), build_gateway(), build_peer(), build_user(), config_parse_variables(), process_dahdi(), and set_config().

01017 {
01018    if (!strcasecmp(flag, "default"))
01019       return 0;
01020    if (!strcasecmp(flag, "omit"))
01021       return AST_CDR_OMIT;
01022    if (!strcasecmp(flag, "billing"))
01023       return AST_CDR_BILLING;
01024    if (!strcasecmp(flag, "documentation"))
01025       return AST_CDR_DOCUMENTATION;
01026    return -1;
01027 }

void ast_cdr_answer ( struct ast_cdr cdr  ) 

Answer a call.

Parameters:
cdr the cdr you wish to associate with the call Starts all CDR stuff necessary for doing CDR when answering a call
Note:
NULL argument is just fine.

Definition at line 687 of file cdr.c.

References ast_cdr::answer, AST_CDR_ANSWERED, AST_CDR_FLAG_ANSLOCKED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_test_flag, ast_tvnow(), ast_tvzero(), check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by ast_bridge_call(), and ast_raw_answer().

00688 {
00689 
00690    for (; cdr; cdr = cdr->next) {
00691       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED)) 
00692          continue;
00693       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00694          continue;
00695       check_post(cdr);
00696       if (cdr->disposition < AST_CDR_ANSWERED)
00697          cdr->disposition = AST_CDR_ANSWERED;
00698       if (ast_tvzero(cdr->answer))
00699          cdr->answer = ast_tvnow();
00700    }
00701 }

struct ast_cdr* ast_cdr_append ( struct ast_cdr cdr,
struct ast_cdr newcdr 
) [read]

Definition at line 1129 of file cdr.c.

References ast_cdr::next.

Referenced by ast_cdr_fork(), ast_cdr_merge(), and attempt_transfer().

01130 {
01131    struct ast_cdr *ret;
01132 
01133    if (cdr) {
01134       ret = cdr;
01135 
01136       while (cdr->next)
01137          cdr = cdr->next;
01138       cdr->next = newcdr;
01139    } else {
01140       ret = newcdr;
01141    }
01142 
01143    return ret;
01144 }

int ast_cdr_appenduserfield ( struct ast_channel chan,
const char *  userfield 
)

Append to CDR user field for channel (stored in CDR).

Definition at line 982 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, len(), ast_cdr::next, and ast_cdr::userfield.

00983 {
00984    struct ast_cdr *cdr = chan->cdr;
00985 
00986    for ( ; cdr ; cdr = cdr->next) {
00987       int len = strlen(cdr->userfield);
00988 
00989       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00990          ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
00991    }
00992 
00993    return 0;
00994 }

void ast_cdr_busy ( struct ast_cdr cdr  ) 

Busy a call.

Parameters:
cdr the cdr you wish to associate with the call Marks the channel disposition as "BUSY" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application. Returns nothing

Definition at line 703 of file cdr.c.

References AST_CDR_BUSY, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by ast_cdr_disposition(), handle_cause(), pbx_builtin_busy(), ring_entry(), and wait_for_answer().

00704 {
00705 
00706    for (; cdr; cdr = cdr->next) {
00707       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00708          check_post(cdr);
00709          if (cdr->disposition < AST_CDR_BUSY)
00710             cdr->disposition = AST_CDR_BUSY;
00711       }
00712    }
00713 }

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

Definition at line 336 of file cdr.c.

References AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_assign(), ast_var_name(), ast_var_value(), var, and ast_cdr::varshead.

Referenced by ast_cdr_dup().

00337 {
00338    struct ast_var_t *variables, *newvariable = NULL;
00339    struct varshead *headpa, *headpb;
00340    const char *var, *val;
00341    int x = 0;
00342 
00343    if (!to_cdr || !from_cdr) /* don't die if one of the pointers is null */
00344       return 0;
00345 
00346    headpa = &from_cdr->varshead;
00347    headpb = &to_cdr->varshead;
00348 
00349    AST_LIST_TRAVERSE(headpa,variables,entries) {
00350       if (variables &&
00351           (var = ast_var_name(variables)) && (val = ast_var_value(variables)) &&
00352           !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
00353          newvariable = ast_var_assign(var, val);
00354          AST_LIST_INSERT_HEAD(headpb, newvariable, entries);
00355          x++;
00356       }
00357    }
00358 
00359    return x;
00360 }

void ast_cdr_detach ( struct ast_cdr cdr  ) 

Detaches the detail record for posting (and freeing) either now or at a later time in bulk with other records during batch mode operation.

Parameters:
cdr Which CDR to detach from the channel thread Prevents the channel thread from blocking on the CDR handling Returns nothing

Definition at line 1234 of file cdr.c.

References ast_calloc, AST_CDR_FLAG_POST_DISABLED, ast_cdr_free(), ast_debug, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, batch, batchmode, batchsize, ast_cdr_batch_item::cdr, cdr_batch_lock, enabled, ast_cdr_batch::head, init_batch(), ast_cdr_batch_item::next, post_cdr(), ast_cdr_batch::size, submit_unscheduled_batch(), and ast_cdr_batch::tail.

Referenced by ast_bridge_call(), ast_cdr_reset(), ast_hangup(), and ast_pbx_outgoing_cdr_failed().

01235 {
01236    struct ast_cdr_batch_item *newtail;
01237    int curr;
01238 
01239    if (!cdr)
01240       return;
01241 
01242    /* maybe they disabled CDR stuff completely, so just drop it */
01243    if (!enabled) {
01244       ast_debug(1, "Dropping CDR !\n");
01245       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01246       ast_cdr_free(cdr);
01247       return;
01248    }
01249 
01250    /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
01251    if (!batchmode) {
01252       post_cdr(cdr);
01253       ast_cdr_free(cdr);
01254       return;
01255    }
01256 
01257    /* otherwise, each CDR gets put into a batch list (at the end) */
01258    ast_debug(1, "CDR detaching from this thread\n");
01259 
01260    /* we'll need a new tail for every CDR */
01261    if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
01262       post_cdr(cdr);
01263       ast_cdr_free(cdr);
01264       return;
01265    }
01266 
01267    /* don't traverse a whole list (just keep track of the tail) */
01268    ast_mutex_lock(&cdr_batch_lock);
01269    if (!batch)
01270       init_batch();
01271    if (!batch->head) {
01272       /* new batch is empty, so point the head at the new tail */
01273       batch->head = newtail;
01274    } else {
01275       /* already got a batch with something in it, so just append a new tail */
01276       batch->tail->next = newtail;
01277    }
01278    newtail->cdr = cdr;
01279    batch->tail = newtail;
01280    curr = batch->size++;
01281    ast_mutex_unlock(&cdr_batch_lock);
01282 
01283    /* if we have enough stuff to post, then do it */
01284    if (curr >= (batchsize - 1))
01285       submit_unscheduled_batch();
01286 }

void ast_cdr_discard ( struct ast_cdr cdr  ) 

the same as a cdr_free call, only with no checks; just get rid of it

Discard and free a CDR record.

Definition at line 441 of file cdr.c.

References ast_cdr_free_vars(), ast_free, ast_cdr::next, and ast_cdr_beitem::next.

Referenced by ast_async_goto(), ast_bridge_call(), ast_cdr_merge(), and ast_channel_free().

00442 {
00443    while (cdr) {
00444       struct ast_cdr *next = cdr->next;
00445 
00446       ast_cdr_free_vars(cdr, 0);
00447       ast_free(cdr);
00448       cdr = next;
00449    }
00450 }

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

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

Referenced by ast_cdr_getvar(), build_csv_record(), build_radius_record(), csv_log(), execute_cb(), manager_log(), and tds_log().

00906 {
00907    switch (disposition) {
00908    case AST_CDR_NULL:
00909       return "NO ANSWER"; /* by default, for backward compatibility */
00910    case AST_CDR_NOANSWER:
00911       return "NO ANSWER";
00912    case AST_CDR_FAILED:
00913       return "FAILED";     
00914    case AST_CDR_BUSY:
00915       return "BUSY";    
00916    case AST_CDR_ANSWERED:
00917       return "ANSWERED";
00918    }
00919    return "UNKNOWN";
00920 }

int ast_cdr_disposition ( struct ast_cdr cdr,
int  cause 
)

Save the result of the call based on the AST_CAUSE_*.

Parameters:
cdr the cdr you wish to associate with the call
cause the AST_CAUSE_* Returns nothing

Definition at line 746 of file cdr.c.

References AST_CAUSE_BUSY, AST_CAUSE_NO_ANSWER, AST_CAUSE_NORMAL, ast_cdr_busy(), ast_cdr_noanswer(), and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), clear_caller(), and findmeexec().

00747 {
00748    int res = 0;
00749 
00750    for (; cdr; cdr = cdr->next) {
00751       switch (cause) {  /* handle all the non failure, busy cases, return 0 not to set disposition,
00752                      return -1 to set disposition to FAILED */
00753       case AST_CAUSE_BUSY:
00754          ast_cdr_busy(cdr);
00755          break;
00756       case AST_CAUSE_NO_ANSWER:
00757          ast_cdr_noanswer(cdr);
00758          break;
00759       case AST_CAUSE_NORMAL:
00760          break;
00761       default:
00762          res = -1;
00763       }
00764    }
00765    return res;
00766 }

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

Duplicate a record.

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 168 of file cdr.c.

References ast_cdr_alloc(), ast_cdr_copy_vars(), ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_async_goto(), ast_bridge_call(), ast_cdr_fork(), ast_cdr_merge(), and ast_cdr_reset().

00169 {
00170    struct ast_cdr *newcdr;
00171    
00172    if (!cdr) /* don't die if we get a null cdr pointer */
00173       return NULL;
00174    newcdr = ast_cdr_alloc();
00175    if (!newcdr)
00176       return NULL;
00177 
00178    memcpy(newcdr, cdr, sizeof(*newcdr));
00179    /* The varshead is unusable, volatile even, after the memcpy so we take care of that here */
00180    memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
00181    ast_cdr_copy_vars(newcdr, cdr);
00182    newcdr->next = NULL;
00183 
00184    return newcdr;
00185 }

void ast_cdr_end ( struct ast_cdr cdr  ) 

End a call.

Parameters:
cdr the cdr you have associated the call with Registers the end of call time in the cdr structure. Returns nothing

Definition at line 879 of file cdr.c.

References ast_cdr::answer, AST_CDR_ANSWERED, AST_CDR_FAILED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_log(), AST_OPT_FLAG_INITIATED_SECONDS, ast_options, ast_test_flag, ast_tvnow(), ast_tvzero(), ast_cdr::billsec, ast_cdr::channel, check_post(), ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, LOG_WARNING, ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by __ast_pbx_run(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_fork(), ast_cdr_reset(), ast_hangup(), ast_pbx_outgoing_cdr_failed(), clear_caller(), and findmeexec().

00880 {
00881    for ( ; cdr ; cdr = cdr->next) {
00882       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00883          continue;
00884       check_post(cdr);
00885       if (ast_tvzero(cdr->end))
00886          cdr->end = ast_tvnow();
00887       if (ast_tvzero(cdr->start)) {
00888          ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
00889          cdr->disposition = AST_CDR_FAILED;
00890       } else
00891          cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
00892       if (ast_tvzero(cdr->answer)) {
00893          if (cdr->disposition == AST_CDR_ANSWERED) {
00894             ast_log(LOG_WARNING, "CDR on channel '%s' has no answer time but is 'ANSWERED'\n", S_OR(cdr->channel, "<unknown>"));
00895             cdr->disposition = AST_CDR_FAILED;
00896          }
00897       } else {
00898          cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec;
00899          if (ast_test_flag(&ast_options, AST_OPT_FLAG_INITIATED_SECONDS))
00900             cdr->billsec += cdr->end.tv_usec > cdr->answer.tv_usec ? 1 : 0;
00901       }
00902    }
00903 }

int ast_cdr_engine_init ( void   ) 

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

Definition at line 1522 of file cdr.c.

References ast_cli_register(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), cdr_batch_lock, cli_status, do_reload(), init_batch(), LOG_ERROR, and sched_context_create().

Referenced by main().

01523 {
01524    int res;
01525 
01526    sched = sched_context_create();
01527    if (!sched) {
01528       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
01529       return -1;
01530    }
01531 
01532    ast_cli_register(&cli_status);
01533 
01534    res = do_reload(0);
01535    if (res) {
01536       ast_mutex_lock(&cdr_batch_lock);
01537       res = init_batch();
01538       ast_mutex_unlock(&cdr_batch_lock);
01539    }
01540 
01541    return res;
01542 }

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1551 of file cdr.c.

References do_reload().

01552 {
01553    return do_reload(1);
01554 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1546 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01547 {
01548    ast_cdr_submit_batch(batchsafeshutdown);
01549 }

void ast_cdr_failed ( struct ast_cdr cdr  ) 

Fail a call.

Parameters:
cdr the cdr you wish to associate with the call Marks the channel disposition as "FAILED" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application. Returns nothing

Definition at line 715 of file cdr.c.

References AST_CDR_FAILED, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten(), clear_caller(), findmeexec(), handle_cause(), and try_calling().

00716 {
00717    for (; cdr; cdr = cdr->next) {
00718       check_post(cdr);
00719       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00720          check_post(cdr);
00721          if (cdr->disposition < AST_CDR_FAILED)
00722             cdr->disposition = AST_CDR_FAILED;
00723       }
00724    }
00725 }

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

Definition at line 923 of file cdr.c.

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

Referenced by _sip_show_peer(), _skinny_show_line(), ast_cdr_getvar(), build_csv_record(), build_radius_record(), csv_log(), manager_log(), sip_show_user(), and tds_log().

00924 {
00925    switch (flag) {
00926    case AST_CDR_OMIT:
00927       return "OMIT";
00928    case AST_CDR_BILLING:
00929       return "BILLING";
00930    case AST_CDR_DOCUMENTATION:
00931       return "DOCUMENTATION";
00932    }
00933    return "Unknown";
00934 }

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

Definition at line 428 of file cdr.c.

References ast_cdr_free_vars(), ast_free, ast_cdr::next, and ast_cdr_beitem::next.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

00429 {
00430 
00431    while (cdr) {
00432       struct ast_cdr *next = cdr->next;
00433 
00434       ast_cdr_free_vars(cdr, 0);
00435       ast_free(cdr);
00436       cdr = next;
00437    }
00438 }

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

Definition at line 407 of file cdr.c.

References AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_cdr_discard(), ast_cdr_fork(), ast_cdr_free(), and ast_cdr_reset().

00408 {
00409 
00410    /* clear variables */
00411    for (; cdr; cdr = recur ? cdr->next : NULL) {
00412       struct ast_var_t *vardata;
00413       struct varshead *headp = &cdr->varshead;
00414       while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
00415          ast_var_delete(vardata);
00416    }
00417 }

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

CDR channel variable retrieval

Definition at line 219 of file cdr.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_disp2str(), ast_cdr_flags2str(), ast_cdr_getvar_internal(), ast_copy_string(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_cdr::billsec, 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::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by ast_cdr_serialize_variables(), cdr_handler(), cdr_read(), odbc_log(), and pgsql_log().

00220 {
00221    const char *fmt = "%Y-%m-%d %T";
00222    const char *varbuf;
00223 
00224    if (!cdr)  /* don't die if the cdr is null */
00225       return;
00226 
00227    *ret = NULL;
00228    /* special vars (the ones from the struct ast_cdr when requested by name) 
00229       I'd almost say we should convert all the stringed vals to vars */
00230 
00231    if (!strcasecmp(name, "clid"))
00232       ast_copy_string(workspace, cdr->clid, workspacelen);
00233    else if (!strcasecmp(name, "src"))
00234       ast_copy_string(workspace, cdr->src, workspacelen);
00235    else if (!strcasecmp(name, "dst"))
00236       ast_copy_string(workspace, cdr->dst, workspacelen);
00237    else if (!strcasecmp(name, "dcontext"))
00238       ast_copy_string(workspace, cdr->dcontext, workspacelen);
00239    else if (!strcasecmp(name, "channel"))
00240       ast_copy_string(workspace, cdr->channel, workspacelen);
00241    else if (!strcasecmp(name, "dstchannel"))
00242       ast_copy_string(workspace, cdr->dstchannel, workspacelen);
00243    else if (!strcasecmp(name, "lastapp"))
00244       ast_copy_string(workspace, cdr->lastapp, workspacelen);
00245    else if (!strcasecmp(name, "lastdata"))
00246       ast_copy_string(workspace, cdr->lastdata, workspacelen);
00247    else if (!strcasecmp(name, "start"))
00248       cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
00249    else if (!strcasecmp(name, "answer"))
00250       cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
00251    else if (!strcasecmp(name, "end"))
00252       cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
00253    else if (!strcasecmp(name, "duration"))
00254       snprintf(workspace, workspacelen, "%ld", cdr->duration ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
00255    else if (!strcasecmp(name, "billsec"))
00256       snprintf(workspace, workspacelen, "%ld", cdr->billsec || cdr->answer.tv_sec == 0 ? cdr->billsec : (long)ast_tvdiff_ms(ast_tvnow(), cdr->answer) / 1000);
00257    else if (!strcasecmp(name, "disposition")) {
00258       if (raw) {
00259          snprintf(workspace, workspacelen, "%ld", cdr->disposition);
00260       } else {
00261          ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
00262       }
00263    } else if (!strcasecmp(name, "amaflags")) {
00264       if (raw) {
00265          snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
00266       } else {
00267          ast_copy_string(workspace, ast_cdr_flags2str(cdr->amaflags), workspacelen);
00268       }
00269    } else if (!strcasecmp(name, "accountcode"))
00270       ast_copy_string(workspace, cdr->accountcode, workspacelen);
00271    else if (!strcasecmp(name, "uniqueid"))
00272       ast_copy_string(workspace, cdr->uniqueid, workspacelen);
00273    else if (!strcasecmp(name, "userfield"))
00274       ast_copy_string(workspace, cdr->userfield, workspacelen);
00275    else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
00276       ast_copy_string(workspace, varbuf, workspacelen);
00277    else
00278       workspace[0] = '\0';
00279 
00280    if (!ast_strlen_zero(workspace))
00281       *ret = workspace;
00282 }

static const char* ast_cdr_getvar_internal ( struct ast_cdr cdr,
const char *  name,
int  recur 
) [static]

Definition at line 187 of file cdr.c.

References AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_name(), ast_var_value(), ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_cdr_getvar().

00188 {
00189    if (ast_strlen_zero(name))
00190       return NULL;
00191 
00192    for (; cdr; cdr = recur ? cdr->next : NULL) {
00193       struct ast_var_t *variables;
00194       struct varshead *headp = &cdr->varshead;
00195       AST_LIST_TRAVERSE(headp, variables, entries) {
00196          if (!strcasecmp(name, ast_var_name(variables)))
00197             return ast_var_value(variables);
00198       }
00199    }
00200 
00201    return NULL;
00202 }

int ast_cdr_init ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

Parameters:
cdr Call Detail Record to use for channel
chan Channel to bind CDR with Initializes a CDR and associates it with a particular channel
Returns:
0 by default

Definition at line 844 of file cdr.c.

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, ast_channel::amaflags, ast_cdr::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_copy_string(), AST_STATE_UP, ast_test_flag, chan, ast_cdr::channel, ast_channel::context, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::name, ast_cdr::next, S_OR, set_one_cid(), ast_channel::uniqueid, and ast_cdr::uniqueid.

Referenced by __ast_channel_alloc_ap(), __ast_request_and_dial(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

00845 {
00846    char *chan;
00847 
00848    for ( ; cdr ; cdr = cdr->next) {
00849       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00850          chan = S_OR(cdr->channel, "<unknown>");
00851          ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
00852          set_one_cid(cdr, c);
00853 
00854          cdr->disposition = (c->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
00855          cdr->amaflags = c->amaflags ? c->amaflags :  ast_default_amaflags;
00856          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00857          /* Destination information */
00858          ast_copy_string(cdr->dst, S_OR(c->macroexten,c->exten), sizeof(cdr->dst));
00859          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext,c->context), sizeof(cdr->dcontext));
00860          /* Unique call identifier */
00861          ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid));
00862       }
00863    }
00864    return 0;
00865 }

int ast_cdr_isset_unanswered ( void   ) 

Definition at line 160 of file cdr.c.

References unanswered.

Referenced by ring_entry(), and try_calling().

00161 {
00162    return unanswered;
00163 }

void ast_cdr_merge ( struct ast_cdr to,
struct ast_cdr from 
)

Move the non-null data from the "from" cdr to the "to" cdr.

Parameters:
to the cdr to get the goodies
from the cdr to give the goodies

Definition at line 496 of file cdr.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_append(), ast_cdr_discard(), AST_CDR_DOCUMENTATION, ast_cdr_dup(), AST_CDR_FLAG_CHILD, AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, AST_CDR_NOANSWER, ast_copy_string(), ast_log(), ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_tv(), ast_tvcmp(), ast_tvzero(), ast_cdr::billsec, cdr_merge_vars(), 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, LOG_WARNING, ast_cdr::next, ast_cdr::src, ast_cdr::start, and ast_cdr::userfield.

00497 {
00498    struct ast_cdr *zcdr;
00499    struct ast_cdr *lto = NULL;
00500    struct ast_cdr *lfrom = NULL;
00501    int discard_from = 0;
00502    
00503    if (!to || !from)
00504       return;
00505 
00506    /* don't merge into locked CDR's -- it's bad business */
00507    if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
00508       zcdr = to; /* safety valve? */
00509       while (to->next) {
00510          lto = to;
00511          to = to->next;
00512       }
00513       
00514       if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
00515          ast_log(LOG_WARNING, "Merging into locked CDR... no choice.");
00516          to = zcdr; /* safety-- if all there are is locked CDR's, then.... ?? */
00517          lto = NULL;
00518       }
00519    }
00520 
00521    if (ast_test_flag(from, AST_CDR_FLAG_LOCKED)) {
00522       struct ast_cdr *llfrom = NULL;
00523       discard_from = 1;
00524       if (lto) {
00525          /* insert the from stuff after lto */
00526          lto->next = from;
00527          lfrom = from;
00528          while (lfrom && lfrom->next) {
00529             if (!lfrom->next->next)
00530                llfrom = lfrom;
00531             lfrom = lfrom->next; 
00532          }
00533          /* rip off the last entry and put a copy of the to at the end */
00534          llfrom->next = to;
00535          from = lfrom;
00536       } else {
00537          /* save copy of the current *to cdr */
00538          struct ast_cdr tcdr;
00539          memcpy(&tcdr, to, sizeof(tcdr));
00540          /* copy in the locked from cdr */
00541          memcpy(to, from, sizeof(*to));
00542          lfrom = from;
00543          while (lfrom && lfrom->next) {
00544             if (!lfrom->next->next)
00545                llfrom = lfrom;
00546             lfrom = lfrom->next; 
00547          }
00548          from->next = NULL;
00549          /* rip off the last entry and put a copy of the to at the end */
00550          if (llfrom == from)
00551             to = to->next = ast_cdr_dup(&tcdr);
00552          else
00553             to = llfrom->next = ast_cdr_dup(&tcdr);
00554          from = lfrom;
00555       }
00556    }
00557    
00558    if (!ast_tvzero(from->start)) {
00559       if (!ast_tvzero(to->start)) {
00560          if (ast_tvcmp(to->start, from->start) > 0 ) {
00561             to->start = from->start; /* use the earliest time */
00562             from->start = ast_tv(0,0); /* we actively "steal" these values */
00563          }
00564          /* else nothing to do */
00565       } else {
00566          to->start = from->start;
00567          from->start = ast_tv(0,0); /* we actively "steal" these values */
00568       }
00569    }
00570    if (!ast_tvzero(from->answer)) {
00571       if (!ast_tvzero(to->answer)) {
00572          if (ast_tvcmp(to->answer, from->answer) > 0 ) {
00573             to->answer = from->answer; /* use the earliest time */
00574             from->answer = ast_tv(0,0); /* we actively "steal" these values */
00575          }
00576          /* we got the earliest answer time, so we'll settle for that? */
00577       } else {
00578          to->answer = from->answer;
00579          from->answer = ast_tv(0,0); /* we actively "steal" these values */
00580       }
00581    }
00582    if (!ast_tvzero(from->end)) {
00583       if (!ast_tvzero(to->end)) {
00584          if (ast_tvcmp(to->end, from->end) < 0 ) {
00585             to->end = from->end; /* use the latest time */
00586             from->end = ast_tv(0,0); /* we actively "steal" these values */
00587             to->duration = to->end.tv_sec - to->start.tv_sec;  /* don't forget to update the duration, billsec, when we set end */
00588             to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
00589          }
00590          /* else, nothing to do */
00591       } else {
00592          to->end = from->end;
00593          from->end = ast_tv(0,0); /* we actively "steal" these values */
00594          to->duration = to->end.tv_sec - to->start.tv_sec;
00595          to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
00596       }
00597    }
00598    if (to->disposition < from->disposition) {
00599       to->disposition = from->disposition;
00600       from->disposition = AST_CDR_NOANSWER;
00601    }
00602    if (ast_strlen_zero(to->lastapp) && !ast_strlen_zero(from->lastapp)) {
00603       ast_copy_string(to->lastapp, from->lastapp, sizeof(to->lastapp));
00604       from->lastapp[0] = 0; /* theft */
00605    }
00606    if (ast_strlen_zero(to->lastdata) && !ast_strlen_zero(from->lastdata)) {
00607       ast_copy_string(to->lastdata, from->lastdata, sizeof(to->lastdata));
00608       from->lastdata[0] = 0; /* theft */
00609    }
00610    if (ast_strlen_zero(to->dcontext) && !ast_strlen_zero(from->dcontext)) {
00611       ast_copy_string(to->dcontext, from->dcontext, sizeof(to->dcontext));
00612       from->dcontext[0] = 0; /* theft */
00613    }
00614    if (ast_strlen_zero(to->dstchannel) && !ast_strlen_zero(from->dstchannel)) {
00615       ast_copy_string(to->dstchannel, from->dstchannel, sizeof(to->dstchannel));
00616       from->dstchannel[0] = 0; /* theft */
00617    }
00618    if (!ast_strlen_zero(from->channel) && (ast_strlen_zero(to->channel) || !strncasecmp(from->channel, "Agent/", 6))) {
00619       ast_copy_string(to->channel, from->channel, sizeof(to->channel));
00620       from->channel[0] = 0; /* theft */
00621    }
00622    if (ast_strlen_zero(to->src) && !ast_strlen_zero(from->src)) {
00623       ast_copy_string(to->src, from->src, sizeof(to->src));
00624       from->src[0] = 0; /* theft */
00625    }
00626    if (ast_strlen_zero(to->clid) && !ast_strlen_zero(from->clid)) {
00627       ast_copy_string(to->clid, from->clid, sizeof(to->clid));
00628       from->clid[0] = 0; /* theft */
00629    }
00630    if (ast_strlen_zero(to->dst) && !ast_strlen_zero(from->dst)) {
00631       ast_copy_string(to->dst, from->dst, sizeof(to->dst));
00632       from->dst[0] = 0; /* theft */
00633    }
00634    if (!to->amaflags)
00635       to->amaflags = AST_CDR_DOCUMENTATION;
00636    if (!from->amaflags)
00637       from->amaflags = AST_CDR_DOCUMENTATION; /* make sure both amaflags are set to something (DOC is default) */
00638    if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (to->amaflags == AST_CDR_DOCUMENTATION && from->amaflags != AST_CDR_DOCUMENTATION)) {
00639       to->amaflags = from->amaflags;
00640    }
00641    if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->accountcode) && !ast_strlen_zero(from->accountcode))) {
00642       ast_copy_string(to->accountcode, from->accountcode, sizeof(to->accountcode));
00643    }
00644    if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->userfield) && !ast_strlen_zero(from->userfield))) {
00645       ast_copy_string(to->userfield, from->userfield, sizeof(to->userfield));
00646    }
00647    /* flags, varsead, ? */
00648    cdr_merge_vars(from, to);
00649 
00650    if (ast_test_flag(from, AST_CDR_FLAG_KEEP_VARS))
00651       ast_set_flag(to, AST_CDR_FLAG_KEEP_VARS);
00652    if (ast_test_flag(from, AST_CDR_FLAG_POSTED))
00653       ast_set_flag(to, AST_CDR_FLAG_POSTED);
00654    if (ast_test_flag(from, AST_CDR_FLAG_LOCKED))
00655       ast_set_flag(to, AST_CDR_FLAG_LOCKED);
00656    if (ast_test_flag(from, AST_CDR_FLAG_CHILD))
00657       ast_set_flag(to, AST_CDR_FLAG_CHILD);
00658    if (ast_test_flag(from, AST_CDR_FLAG_POST_DISABLED))
00659       ast_set_flag(to, AST_CDR_FLAG_POST_DISABLED);
00660 
00661    /* last, but not least, we need to merge any forked CDRs to the 'to' cdr */
00662    while (from->next) {
00663       /* just rip 'em off the 'from' and insert them on the 'to' */
00664       zcdr = from->next;
00665       from->next = zcdr->next;
00666       zcdr->next = NULL;
00667       /* zcdr is now ripped from the current list; */
00668       ast_cdr_append(to, zcdr);
00669    }
00670    if (discard_from)
00671       ast_cdr_discard(from);
00672 }

void ast_cdr_noanswer ( struct ast_cdr cdr  ) 

A call wasn't answered.

Parameters:
cdr the cdr you wish to associate with the call Marks the channel disposition as "NO ANSWER" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application.

Definition at line 727 of file cdr.c.

References AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POSTED, AST_CDR_NOANSWER, ast_log(), ast_strlen_zero(), ast_test_flag, chan, ast_cdr::channel, ast_cdr::disposition, LOG_WARNING, and ast_cdr::next.

Referenced by ast_cdr_disposition(), handle_cause(), queue_exec(), try_calling(), and wait_for_answer().

00728 {
00729    char *chan; 
00730 
00731    while (cdr) {
00732       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00733          chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
00734          if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
00735             ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
00736          if (cdr->disposition < AST_CDR_NOANSWER)
00737             cdr->disposition = AST_CDR_NOANSWER;
00738       }
00739       cdr = cdr->next;
00740    }
00741 }

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

Register a CDR handling engine.

Register a CDR driver. Each registered CDR driver generates a CDR

Returns:
0 on success, -1 on failure

Definition at line 108 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, ast_cdr_beitem::be, ast_cdr_beitem::desc, ast_cdr_beitem::list, LOG_WARNING, and ast_cdr_beitem::name.

Referenced by config_module(), load_config(), load_module(), odbc_load_module(), and unload_module().

00109 {
00110    struct ast_cdr_beitem *i = NULL;
00111 
00112    if (!name)
00113       return -1;
00114 
00115    if (!be) {
00116       ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
00117       return -1;
00118    }
00119 
00120    AST_RWLIST_WRLOCK(&be_list);
00121    AST_RWLIST_TRAVERSE(&be_list, i, list) {
00122       if (!strcasecmp(name, i->name)) {
00123          ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
00124          AST_RWLIST_UNLOCK(&be_list);
00125          return -1;
00126       }
00127    }
00128 
00129    if (!(i = ast_calloc(1, sizeof(*i))))  
00130       return -1;
00131 
00132    i->be = be;
00133    ast_copy_string(i->name, name, sizeof(i->name));
00134    ast_copy_string(i->desc, desc, sizeof(i->desc));
00135 
00136    AST_RWLIST_INSERT_HEAD(&be_list, i, list);
00137    AST_RWLIST_UNLOCK(&be_list);
00138 
00139    return 0;
00140 }

void ast_cdr_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

Reset the detail record, optionally posting it first.

Parameters:
cdr which cdr to act upon
flags |AST_CDR_FLAG_POSTED whether or not to post the cdr first before resetting it |AST_CDR_FLAG_LOCKED whether or not to reset locked CDR's

Definition at line 1062 of file cdr.c.

References ast_cdr::answer, ast_cdr_detach(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POST_ENABLE, AST_CDR_FLAG_POSTED, ast_cdr_free_vars(), AST_CDR_NOANSWER, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, ast_cdr::next, and ast_cdr::start.

Referenced by ast_cdr_fork(), dial_exec_full(), disa_exec(), and pbx_builtin_resetcdr().

01063 {
01064    struct ast_cdr *duplicate;
01065    struct ast_flags flags = { 0 };
01066 
01067    if (_flags)
01068       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
01069 
01070    for ( ; cdr ; cdr = cdr->next) {
01071       /* Detach if post is requested */
01072       if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01073          if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
01074             ast_cdr_end(cdr);
01075             if ((duplicate = ast_cdr_dup(cdr))) {
01076                ast_cdr_detach(duplicate);
01077             }
01078             ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
01079          }
01080 
01081          /* enable CDR only */
01082          if (ast_test_flag(&flags, AST_CDR_FLAG_POST_ENABLE)) {
01083             ast_clear_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01084             continue;
01085          }
01086 
01087          /* clear variables */
01088          if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
01089             ast_cdr_free_vars(cdr, 0);
01090          }
01091 
01092          /* Reset to initial state */
01093          ast_clear_flag(cdr, AST_FLAGS_ALL); 
01094          memset(&cdr->start, 0, sizeof(cdr->start));
01095          memset(&cdr->end, 0, sizeof(cdr->end));
01096          memset(&cdr->answer, 0, sizeof(cdr->answer));
01097          cdr->billsec = 0;
01098          cdr->duration = 0;
01099          ast_cdr_start(cdr);
01100          cdr->disposition = AST_CDR_NOANSWER;
01101       }
01102    }
01103 }

int ast_cdr_serialize_variables ( struct ast_cdr cdr,
struct ast_str **  buf,
char  delim,
char  sep,
int  recur 
)

Definition at line 362 of file cdr.c.

References ast_cdr_getvar(), AST_LIST_TRAVERSE, ast_log(), ast_str_append(), ast_str_reset(), ast_strlen_zero(), ast_var_name(), ast_var_value(), cdr_readonly_vars, ast_var_t::entries, LOG_ERROR, ast_cdr::next, total, var, and ast_cdr::varshead.

Referenced by handle_showchan().

00363 {
00364    struct ast_var_t *variables;
00365    const char *var, *val;
00366    char *tmp;
00367    char workspace[256];
00368    int total = 0, x = 0, i;
00369 
00370    ast_str_reset(*buf);
00371 
00372    for (; cdr; cdr = recur ? cdr->next : NULL) {
00373       if (++x > 1)
00374          ast_str_append(buf, 0, "\n");
00375 
00376       AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
00377          if (variables &&
00378              (var = ast_var_name(variables)) && (val = ast_var_value(variables)) &&
00379              !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
00380             if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, val, sep) < 0) {
00381                ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
00382                break;
00383             } else
00384                total++;
00385          } else 
00386             break;
00387       }
00388 
00389       for (i = 0; cdr_readonly_vars[i]; i++) {
00390          workspace[0] = 0; /* null out the workspace, because the cdr_get_tv() won't write anything if time is NULL, so you get old vals */
00391          ast_cdr_getvar(cdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
00392          if (!tmp)
00393             continue;
00394          
00395          if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, tmp, sep) < 0) {
00396             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
00397             break;
00398          } else
00399             total++;
00400       }
00401    }
00402 
00403    return total;
00404 }

int ast_cdr_setaccount ( struct ast_channel chan,
const char *  account 
)

Set account code, will generate AMI event.

Definition at line 936 of file cdr.c.

References ast_cdr::accountcode, accountcode, ast_channel::accountcode, AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, buf, ast_channel::cdr, EVENT_FLAG_CALL, manager_event, ast_channel::name, ast_cdr::next, and ast_channel::uniqueid.

Referenced by __ast_request_and_dial(), ast_bridge_call(), ast_call_forward(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), auth_exec(), cdr_write(), and rpt_call().

00937 {
00938    struct ast_cdr *cdr = chan->cdr;
00939    char buf[BUFSIZ/2] = "";
00940    if (!ast_strlen_zero(chan->accountcode))
00941       ast_copy_string(buf, chan->accountcode, sizeof(buf));
00942 
00943    ast_string_field_set(chan, accountcode, account);
00944    for ( ; cdr ; cdr = cdr->next) {
00945       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00946          ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode));
00947       }
00948    }
00949 
00950    /* Signal change of account code to manager */
00951    manager_event(EVENT_FLAG_CALL, "NewAccountCode", "Channel: %s\r\nUniqueid: %s\r\nAccountCode: %s\r\nOldAccountCode: %s\r\n", chan->name, chan->uniqueid, chan->accountcode, buf);
00952    return 0;
00953 }

int ast_cdr_setamaflags ( struct ast_channel chan,
const char *  flag 
)

Set AMA flags for channel.

Definition at line 955 of file cdr.c.

References ast_cdr::amaflags, ast_cdr_amaflags2int(), AST_CDR_FLAG_LOCKED, ast_test_flag, ast_channel::cdr, and ast_cdr::next.

Referenced by cdr_write(), and pbx_builtin_setamaflags().

00956 {
00957    struct ast_cdr *cdr;
00958    int newflag = ast_cdr_amaflags2int(flag);
00959    if (newflag) {
00960       for (cdr = chan->cdr; cdr; cdr = cdr->next) {
00961          if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00962             cdr->amaflags = newflag;
00963          }
00964       }
00965    }
00966 
00967    return 0;
00968 }

void ast_cdr_setanswer ( struct ast_cdr cdr,
struct timeval  t 
)

Set the answer time for a call.

Parameters:
cdr the cdr you wish to associate with the call
t the answer time Starts all CDR stuff necessary for doing CDR when answering a call NULL argument is just fine.

Definition at line 790 of file cdr.c.

References ast_cdr::answer, AST_CDR_FLAG_ANSLOCKED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), and ast_cdr::next.

00791 {
00792 
00793    for (; cdr; cdr = cdr->next) {
00794       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
00795          continue;
00796       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00797          continue;
00798       check_post(cdr);
00799       cdr->answer = t;
00800    }
00801 }

void ast_cdr_setapp ( struct ast_cdr cdr,
const char *  app,
const char *  data 
)

Set the last executed application.

Parameters:
cdr which cdr to act upon
app the name of the app you wish to change it to
data the data you want in the data field of app you set it to Changes the value of the last executed app Returns nothing

Definition at line 778 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, check_post(), ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::next, and S_OR.

Referenced by __ast_request_and_dial(), agi_handle_command(), clear_caller(), findmeexec(), and pbx_exec().

00779 {
00780 
00781    for (; cdr; cdr = cdr->next) {
00782       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00783          check_post(cdr);
00784          ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp));
00785          ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata));
00786       }
00787    }
00788 }

int ast_cdr_setcid ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

Parameters:
cdr Call Detail Record to use for channel
chan Channel to bind CDR with Initializes a CDR and associates it with a particular channel
Returns:
0 by default

Definition at line 835 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, ast_cdr::next, and set_one_cid().

Referenced by ast_bridge_call(), and callerid_write().

00836 {
00837    for (; cdr; cdr = cdr->next) {
00838       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00839          set_one_cid(cdr, c);
00840    }
00841    return 0;
00842 }

void ast_cdr_setdestchan ( struct ast_cdr cdr,
const char *  chan 
)

Set the destination channel, if there was one.

Parameters:
cdr Which cdr it's applied to
chan Channel to which dest will be Sets the destination channel the CDR is applied to Returns nothing

Definition at line 768 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, check_post(), ast_cdr::dstchannel, and ast_cdr::next.

Referenced by dial_exec_full(), park_exec_full(), ring_entry(), and try_calling().

00769 {
00770    for (; cdr; cdr = cdr->next) {
00771       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00772          check_post(cdr);
00773          ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
00774       }
00775    }
00776 }

void ast_cdr_setdisposition ( struct ast_cdr cdr,
long int  disposition 
)

Set the disposition for a call.

Parameters:
cdr the cdr you wish to associate with the call
disposition the new disposition Set the disposition on a call. NULL argument is just fine.

Definition at line 803 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), ast_cdr::disposition, and ast_cdr::next.

00804 {
00805 
00806    for (; cdr; cdr = cdr->next) {
00807       if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00808          continue;
00809       check_post(cdr);
00810       cdr->disposition = disposition;
00811    }
00812 }

int ast_cdr_setuserfield ( struct ast_channel chan,
const char *  userfield 
)

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

Definition at line 970 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, ast_cdr::next, and ast_cdr::userfield.

Referenced by __agent_start_monitoring(), cdr_write(), handle_request_info(), and start_monitor_exec().

00971 {
00972    struct ast_cdr *cdr = chan->cdr;
00973 
00974    for ( ; cdr ; cdr = cdr->next) {
00975       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 
00976          ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
00977    }
00978 
00979    return 0;
00980 }

int ast_cdr_setvar ( struct ast_cdr cdr,
const char *  name,
const char *  value,
int  recur 
)

Set a CDR channel variable

Note:
You can't set the CDR variables that belong to the actual CDR record, like "billsec".

Definition at line 292 of file cdr.c.

References AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_test_flag, ast_var_assign(), ast_var_delete(), ast_var_name(), cdr_readonly_vars, LOG_ERROR, ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_cdr_fork(), cdr_write(), and set_one_cid().

00293 {
00294    struct ast_var_t *newvariable;
00295    struct varshead *headp;
00296    int x;
00297    
00298    if (!cdr)  /* don't die if the cdr is null */
00299       return -1;
00300    
00301    for (x = 0; cdr_readonly_vars[x]; x++) {
00302       if (!strcasecmp(name, cdr_readonly_vars[x])) {
00303          ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!.\n", name);
00304          return -1;
00305       }
00306    }
00307 
00308    if (!cdr) {
00309       ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n");
00310       return -1;
00311    }
00312 
00313    for (; cdr; cdr = recur ? cdr->next : NULL) {
00314       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00315          continue;
00316       headp = &cdr->varshead;
00317       AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
00318          if (!strcasecmp(ast_var_name(newvariable), name)) {
00319             /* there is already such a variable, delete it */
00320             AST_LIST_REMOVE_CURRENT(entries);
00321             ast_var_delete(newvariable);
00322             break;
00323          }
00324       }
00325       AST_LIST_TRAVERSE_SAFE_END;
00326       
00327       if (value) {
00328          newvariable = ast_var_assign(name, value);
00329          AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00330       }
00331    }
00332 
00333    return 0;
00334 }

void ast_cdr_specialized_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

Reset the detail record times, flags

Parameters:
cdr which cdr to act upon
flags |AST_CDR_FLAG_POSTED whether or not to post the cdr first before resetting it |AST_CDR_FLAG_LOCKED whether or not to reset locked CDR's

Definition at line 1105 of file cdr.c.

References ast_cdr::answer, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, and ast_cdr::start.

Referenced by ast_bridge_call().

01106 {
01107    struct ast_flags flags = { 0 };
01108 
01109    if (_flags)
01110       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
01111    
01112    /* Reset to initial state */
01113    if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) { /* But do NOT lose the NoCDR() setting */
01114       ast_clear_flag(cdr, AST_FLAGS_ALL); 
01115       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01116    } else {
01117       ast_clear_flag(cdr, AST_FLAGS_ALL); 
01118    }
01119    
01120    memset(&cdr->start, 0, sizeof(cdr->start));
01121    memset(&cdr->end, 0, sizeof(cdr->end));
01122    memset(&cdr->answer, 0, sizeof(cdr->answer));
01123    cdr->billsec = 0;
01124    cdr->duration = 0;
01125    ast_cdr_start(cdr);
01126    cdr->disposition = AST_CDR_NULL;
01127 }

void ast_cdr_start ( struct ast_cdr cdr  ) 

Start a call.

Parameters:
cdr the cdr you wish to associate with the call Starts all CDR stuff necessary for monitoring a call Returns nothing

Definition at line 674 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, ast_tvnow(), chan, ast_cdr::channel, check_post(), ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by __ast_channel_alloc_ap(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_reset(), ast_cdr_specialized_reset(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

00675 {
00676    char *chan; 
00677 
00678    for (; cdr; cdr = cdr->next) {
00679       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00680          chan = S_OR(cdr->channel, "<unknown>");
00681          check_post(cdr);
00682          cdr->start = ast_tvnow();
00683       }
00684    }
00685 }

void ast_cdr_submit_batch ( int  shutdown  ) 

Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines.

Parameters:
shutdown Whether or not we are shutting down Blocks the asterisk shutdown procedures until the CDR data is submitted. Returns nothing

Definition at line 1183 of file cdr.c.

References ast_debug, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_detached_background, AST_PTHREADT_NULL, batch, batchscheduleronly, cdr_batch_lock, do_batch_backend_process(), ast_cdr_batch::head, LOG_WARNING, and reset_batch().

Referenced by ast_cdr_engine_term(), and submit_scheduled_batch().

01184 {
01185    struct ast_cdr_batch_item *oldbatchitems = NULL;
01186    pthread_t batch_post_thread = AST_PTHREADT_NULL;
01187 
01188    /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
01189    if (!batch || !batch->head)
01190       return;
01191 
01192    /* move the old CDRs aside, and prepare a new CDR batch */
01193    ast_mutex_lock(&cdr_batch_lock);
01194    oldbatchitems = batch->head;
01195    reset_batch();
01196    ast_mutex_unlock(&cdr_batch_lock);
01197 
01198    /* if configured, spawn a new thread to post these CDRs,
01199       also try to save as much as possible if we are shutting down safely */
01200    if (batchscheduleronly || do_shutdown) {
01201       ast_debug(1, "CDR single-threaded batch processing begins now\n");
01202       do_batch_backend_process(oldbatchitems);
01203    } else {
01204       if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
01205          ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
01206          do_batch_backend_process(oldbatchitems);
01207       } else {
01208          ast_debug(1, "CDR multi-threaded batch processing begins now\n");
01209       }
01210    }
01211 }

void ast_cdr_unregister ( const char *  name  ) 

Unregister a CDR handling engine.

unregister a CDR driver

Definition at line 143 of file cdr.c.

References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_cdr_beitem::list, and ast_cdr_beitem::name.

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

00144 {
00145    struct ast_cdr_beitem *i = NULL;
00146 
00147    AST_RWLIST_WRLOCK(&be_list);
00148    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
00149       if (!strcasecmp(name, i->name)) {
00150          AST_RWLIST_REMOVE_CURRENT(list);
00151          ast_verb(2, "Unregistered '%s' CDR backend\n", name);
00152          ast_free(i);
00153          break;
00154       }
00155    }
00156    AST_RWLIST_TRAVERSE_SAFE_END;
00157    AST_RWLIST_UNLOCK(&be_list);
00158 }

int ast_cdr_update ( struct ast_channel chan  ) 

Update CDR on a channel

Definition at line 996 of file cdr.c.

References ast_channel::accountcode, ast_cdr::accountcode, AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, ast_channel::context, ast_cdr::dcontext, ast_cdr::dst, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_cdr::next, S_OR, and set_one_cid().

Referenced by __ast_pbx_run(), __ast_request_and_dial(), ast_bridge_call(), cb_events(), clear_caller(), findmeexec(), and local_call().

00997 {
00998    struct ast_cdr *cdr = c->cdr;
00999 
01000    for ( ; cdr ; cdr = cdr->next) {
01001       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01002          set_one_cid(cdr, c);
01003 
01004          /* Copy account code et-al */ 
01005          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
01006          
01007          /* Destination information */ /* XXX privilege macro* ? */
01008          ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst));
01009          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext));
01010       }
01011    }
01012 
01013    return 0;
01014 }

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

Definition at line 204 of file cdr.c.

References ast_localtime(), and ast_strftime().

Referenced by ast_cdr_getvar().

00205 {
00206    if (fmt == NULL) {   /* raw mode */
00207       snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
00208    } else {
00209       if (when.tv_sec) {
00210          struct ast_tm tm;
00211          
00212          ast_localtime(&when, &tm, NULL);
00213          ast_strftime(buf, bufsize, fmt, &tm);
00214       }
00215    }
00216 }

static void cdr_merge_vars ( struct ast_cdr to,
struct ast_cdr from 
) [static]

Definition at line 461 of file cdr.c.

References AST_LIST_MOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_var_name(), ast_var_value(), LOG_NOTICE, and ast_cdr::varshead.

Referenced by ast_cdr_merge().

00462 {
00463    struct ast_var_t *variablesfrom,*variablesto;
00464    struct varshead *headpfrom = &to->varshead;
00465    struct varshead *headpto = &from->varshead;
00466    AST_LIST_TRAVERSE_SAFE_BEGIN(headpfrom, variablesfrom, entries) {
00467       /* for every var in from, stick it in to */
00468       const char *fromvarname, *fromvarval;
00469       const char *tovarname = NULL, *tovarval = NULL;
00470       fromvarname = ast_var_name(variablesfrom);
00471       fromvarval = ast_var_value(variablesfrom);
00472       tovarname = 0;
00473 
00474       /* now, quick see if that var is in the 'to' cdr already */
00475       AST_LIST_TRAVERSE(headpto, variablesto, entries) {
00476 
00477          /* now, quick see if that var is in the 'to' cdr already */
00478          if ( strcasecmp(fromvarname, ast_var_name(variablesto)) == 0 ) {
00479             tovarname = ast_var_name(variablesto);
00480             tovarval = ast_var_value(variablesto);
00481             break;
00482          }
00483       }
00484       if (tovarname && strcasecmp(fromvarval,tovarval) != 0) {  /* this message here to see how irritating the userbase finds it */
00485          ast_log(LOG_NOTICE, "Merging CDR's: variable %s value %s dropped in favor of value %s\n", tovarname, fromvarval, tovarval);
00486          continue;
00487       } else if (tovarname && strcasecmp(fromvarval,tovarval) == 0) /* if they are the same, the job is done */
00488          continue;
00489 
00490       /* rip this var out of the from cdr, and stick it in the to cdr */
00491       AST_LIST_MOVE_CURRENT(headpto, entries);
00492    }
00493    AST_LIST_TRAVERSE_SAFE_END;
00494 }

int check_cdr_enabled ( void   ) 

Return TRUE if CDR subsystem is enabled.

Definition at line 100 of file cdr.c.

References enabled.

Referenced by action_coresettings(), and handle_show_settings().

00101 {
00102    return enabled;
00103 }

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

Definition at line 420 of file cdr.c.

References AST_CDR_FLAG_POSTED, ast_log(), ast_test_flag, ast_cdr::channel, LOG_NOTICE, and S_OR.

Referenced by ast_cdr_answer(), ast_cdr_busy(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_setanswer(), ast_cdr_setapp(), ast_cdr_setdestchan(), ast_cdr_setdisposition(), ast_cdr_start(), and post_cdr().

00421 {
00422    if (!cdr)
00423       return;
00424    if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
00425       ast_log(LOG_NOTICE, "CDR on channel '%s' already posted\n", S_OR(cdr->channel, "<unknown>"));
00426 }

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

Definition at line 1166 of file cdr.c.

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

Referenced by ast_cdr_submit_batch().

01167 {
01168    struct ast_cdr_batch_item *processeditem;
01169    struct ast_cdr_batch_item *batchitem = data;
01170 
01171    /* Push each CDR into storage mechanism(s) and free all the memory */
01172    while (batchitem) {
01173       post_cdr(batchitem->cdr);
01174       ast_cdr_free(batchitem->cdr);
01175       processeditem = batchitem;
01176       batchitem = batchitem->next;
01177       ast_free(processeditem);
01178    }
01179 
01180    return NULL;
01181 }

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

Definition at line 1288 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, and cdr_pending_lock.

Referenced by do_reload().

01289 {
01290    struct timespec timeout;
01291    int schedms;
01292    int numevents = 0;
01293 
01294    for (;;) {
01295       struct timeval now;
01296       schedms = ast_sched_wait(sched);
01297       /* this shouldn't happen, but provide a 1 second default just in case */
01298       if (schedms <= 0)
01299          schedms = 1000;
01300       now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
01301       timeout.tv_sec = now.tv_sec;
01302       timeout.tv_nsec = now.tv_usec * 1000;
01303       /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
01304       ast_mutex_lock(&cdr_pending_lock);
01305       ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
01306       numevents = ast_sched_runq(sched);
01307       ast_mutex_unlock(&cdr_pending_lock);
01308       ast_debug(2, "Processed %d scheduled CDR batches from the run queue\n", numevents);
01309    }
01310 
01311    return NULL;
01312 }

static int do_reload ( int  reload  )  [static]

Definition at line 1396 of file cdr.c.

References ast_cdr_engine_term(), ast_cli_register(), ast_cli_unregister(), ast_cond_destroy(), ast_cond_init(), ast_config_destroy(), ast_config_load2(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN, AST_OPT_FLAG_INITIATED_SECONDS, ast_options, ast_pthread_create_background, AST_PTHREADT_NULL, ast_register_atexit(), ast_sched_add(), AST_SCHED_DEL, ast_set2_flag, ast_true(), ast_unregister_atexit(), ast_variable_retrieve(), BATCH_SAFE_SHUTDOWN_DEFAULT, BATCH_SCHEDULER_ONLY_DEFAULT, BATCH_SIZE_DEFAULT, BATCH_TIME_DEFAULT, batchmode, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_batch_lock, cdr_pending_cond, cdr_sched, cdr_thread, cli_submit, config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, do_cdr(), enabled, EVENT_FLAG_SYSTEM, LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_event, submit_scheduled_batch(), and unanswered.

Referenced by ast_cdr_engine_init(), and ast_cdr_engine_reload().

01397 {
01398    struct ast_config *config;
01399    const char *enabled_value;
01400    const char *unanswered_value;
01401    const char *batched_value;
01402    const char *scheduleronly_value;
01403    const char *batchsafeshutdown_value;
01404    const char *size_value;
01405    const char *time_value;
01406    const char *end_before_h_value;
01407    const char *initiatedseconds_value;
01408    int cfg_size;
01409    int cfg_time;
01410    int was_enabled;
01411    int was_batchmode;
01412    int res=0;
01413    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01414 
01415    if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
01416       return 0;
01417    if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEUNCHANGED || config == CONFIG_STATUS_FILEINVALID) {
01418       return 0;
01419    }
01420 
01421    ast_mutex_lock(&cdr_batch_lock);
01422 
01423    batchsize = BATCH_SIZE_DEFAULT;
01424    batchtime = BATCH_TIME_DEFAULT;
01425    batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
01426    batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
01427    was_enabled = enabled;
01428    was_batchmode = batchmode;
01429    enabled = 1;
01430    batchmode = 0;
01431 
01432    /* don't run the next scheduled CDR posting while reloading */
01433    AST_SCHED_DEL(sched, cdr_sched);
01434 
01435    if (config) {
01436       if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
01437          enabled = ast_true(enabled_value);
01438       }
01439       if ((unanswered_value = ast_variable_retrieve(config, "general", "unanswered"))) {
01440          unanswered = ast_true(unanswered_value);
01441       }
01442       if ((batched_value = ast_variable_retrieve(config, "general", "batch"))) {
01443          batchmode = ast_true(batched_value);
01444       }
01445       if ((scheduleronly_value = ast_variable_retrieve(config, "general", "scheduleronly"))) {
01446          batchscheduleronly = ast_true(scheduleronly_value);
01447       }
01448       if ((batchsafeshutdown_value = ast_variable_retrieve(config, "general", "safeshutdown"))) {
01449          batchsafeshutdown = ast_true(batchsafeshutdown_value);
01450       }
01451       if ((size_value = ast_variable_retrieve(config, "general", "size"))) {
01452          if (sscanf(size_value, "%30d", &cfg_size) < 1)
01453             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", size_value);
01454          else if (cfg_size < 0)
01455             ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
01456          else
01457             batchsize = cfg_size;
01458       }
01459       if ((time_value = ast_variable_retrieve(config, "general", "time"))) {
01460          if (sscanf(time_value, "%30d", &cfg_time) < 1)
01461             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", time_value);
01462          else if (cfg_time < 0)
01463             ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
01464          else
01465             batchtime = cfg_time;
01466       }
01467       if ((end_before_h_value = ast_variable_retrieve(config, "general", "endbeforehexten")))
01468          ast_set2_flag(&ast_options, ast_true(end_before_h_value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
01469       if ((initiatedseconds_value = ast_variable_retrieve(config, "general", "initiatedseconds")))
01470          ast_set2_flag(&ast_options, ast_true(initiatedseconds_value), AST_OPT_FLAG_INITIATED_SECONDS);
01471    }
01472 
01473    if (enabled && !batchmode) {
01474       ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
01475    } else if (enabled && batchmode) {
01476       cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01477       ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
01478    } else {
01479       ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
01480    }
01481 
01482    /* if this reload enabled the CDR batch mode, create the background thread
01483       if it does not exist */
01484    if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
01485       ast_cond_init(&cdr_pending_cond, NULL);
01486       if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
01487          ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
01488          AST_SCHED_DEL(sched, cdr_sched);
01489       } else {
01490          ast_cli_register(&cli_submit);
01491          ast_register_atexit(ast_cdr_engine_term);
01492          res = 0;
01493       }
01494    /* if this reload disabled the CDR and/or batch mode and there is a background thread,
01495       kill it */
01496    } else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
01497       /* wake up the thread so it will exit */
01498       pthread_cancel(cdr_thread);
01499       pthread_kill(cdr_thread, SIGURG);
01500       pthread_join(cdr_thread, NULL);
01501       cdr_thread = AST_PTHREADT_NULL;
01502       ast_cond_destroy(&cdr_pending_cond);
01503       ast_cli_unregister(&cli_submit);
01504       ast_unregister_atexit(ast_cdr_engine_term);
01505       res = 0;
01506       /* if leaving batch mode, then post the CDRs in the batch,
01507          and don't reschedule, since we are stopping CDR logging */
01508       if (!batchmode && was_batchmode) {
01509          ast_cdr_engine_term();
01510       }
01511    } else {
01512       res = 0;
01513    }
01514 
01515    ast_mutex_unlock(&cdr_batch_lock);
01516    ast_config_destroy(config);
01517    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: CDR\r\nMessage: CDR subsystem reload requested\r\n");
01518 
01519    return res;
01520 }

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

Definition at line 1314 of file cdr.c.

References ast_cli_args::argc, ast_cli(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_sched_when(), batch, batchmode, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_sched, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, enabled, ESS, ast_cli_args::fd, ast_cdr_beitem::list, ast_cdr_beitem::name, ast_cdr_batch::size, unanswered, and ast_cli_entry::usage.

01315 {
01316    struct ast_cdr_beitem *beitem=NULL;
01317    int cnt=0;
01318    long nextbatchtime=0;
01319 
01320    switch (cmd) {
01321    case CLI_INIT:
01322       e->command = "cdr show status";
01323       e->usage = 
01324          "Usage: cdr show status\n"
01325          "  Displays the Call Detail Record engine system status.\n";
01326       return NULL;
01327    case CLI_GENERATE:
01328       return NULL;
01329    }
01330 
01331    if (a->argc > 3)
01332       return CLI_SHOWUSAGE;
01333 
01334    ast_cli(a->fd, "\n");
01335    ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
01336    ast_cli(a->fd, "----------------------------------\n");
01337    ast_cli(a->fd, "  Logging:                    %s\n", enabled ? "Enabled" : "Disabled");
01338    ast_cli(a->fd, "  Mode:                       %s\n", batchmode ? "Batch" : "Simple");
01339    if (enabled) {
01340       ast_cli(a->fd, "  Log unanswered calls:       %s\n\n", unanswered ? "Yes" : "No");
01341       if (batchmode) {
01342          ast_cli(a->fd, "* Batch Mode Settings\n");
01343          ast_cli(a->fd, "  -------------------\n");
01344          if (batch)
01345             cnt = batch->size;
01346          if (cdr_sched > -1)
01347             nextbatchtime = ast_sched_when(sched, cdr_sched);
01348          ast_cli(a->fd, "  Safe shutdown:              %s\n", batchsafeshutdown ? "Enabled" : "Disabled");
01349          ast_cli(a->fd, "  Threading model:            %s\n", batchscheduleronly ? "Scheduler only" : "Scheduler plus separate threads");
01350          ast_cli(a->fd, "  Current batch size:         %d record%s\n", cnt, ESS(cnt));
01351          ast_cli(a->fd, "  Maximum batch size:         %d record%s\n", batchsize, ESS(batchsize));
01352          ast_cli(a->fd, "  Maximum batch time:         %d second%s\n", batchtime, ESS(batchtime));
01353          ast_cli(a->fd, "  Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
01354       }
01355       ast_cli(a->fd, "* Registered Backends\n");
01356       ast_cli(a->fd, "  -------------------\n");
01357       AST_RWLIST_RDLOCK(&be_list);
01358       if (AST_RWLIST_EMPTY(&be_list)) {
01359          ast_cli(a->fd, "    (none)\n");
01360       } else {
01361          AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
01362             ast_cli(a->fd, "    %s\n", beitem->name);
01363          }
01364       }
01365       AST_RWLIST_UNLOCK(&be_list);
01366       ast_cli(a->fd, "\n");
01367    }
01368 
01369    return CLI_SUCCESS;
01370 }

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

Definition at line 1372 of file cdr.c.

References ast_cli_args::argc, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, submit_unscheduled_batch(), and ast_cli_entry::usage.

01373 {
01374    switch (cmd) {
01375    case CLI_INIT:
01376       e->command = "cdr submit";
01377       e->usage = 
01378          "Usage: cdr submit\n"
01379          "       Posts all pending batched CDR data to the configured CDR backend engine modules.\n";
01380       return NULL;
01381    case CLI_GENERATE:
01382       return NULL;
01383    }
01384    if (a->argc > 2)
01385       return CLI_SHOWUSAGE;
01386 
01387    submit_unscheduled_batch();
01388    ast_cli(a->fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
01389 
01390    return CLI_SUCCESS;
01391 }

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

Definition at line 1155 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

01156 {
01157    /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
01158    if (!(batch = ast_malloc(sizeof(*batch))))
01159       return -1;
01160 
01161    reset_batch();
01162 
01163    return 0;
01164 }

static void post_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 1029 of file cdr.c.

References AST_CDR_ANSWERED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_ORIGINATED, AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_cdr_beitem::be, chan, ast_cdr::channel, check_post(), ast_cdr::disposition, ast_cdr::dstchannel, ast_cdr_beitem::list, ast_cdr::next, S_OR, and unanswered.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

01030 {
01031    char *chan;
01032    struct ast_cdr_beitem *i;
01033 
01034    for ( ; cdr ; cdr = cdr->next) {
01035       if (!unanswered && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
01036          /* For people, who don't want to see unanswered single-channel events */
01037          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01038          continue;
01039       }
01040 
01041       /* don't post CDRs that are for dialed channels unless those
01042        * channels were originated from asterisk (pbx_spool, manager,
01043        * cli) */
01044       if (ast_test_flag(cdr, AST_CDR_FLAG_DIALED) && !ast_test_flag(cdr, AST_CDR_FLAG_ORIGINATED)) {
01045          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01046          continue;
01047       }
01048 
01049       chan = S_OR(cdr->channel, "<unknown>");
01050       check_post(cdr);
01051       ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
01052       if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
01053          continue;
01054       AST_RWLIST_RDLOCK(&be_list);
01055       AST_RWLIST_TRAVERSE(&be_list, i, list) {
01056          i->be(cdr);
01057       }
01058       AST_RWLIST_UNLOCK(&be_list);
01059    }
01060 }

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

Definition at line 1147 of file cdr.c.

References batch, ast_cdr_batch::head, ast_cdr_batch::size, and ast_cdr_batch::tail.

Referenced by ast_cdr_submit_batch(), and init_batch().

01148 {
01149    batch->size = 0;
01150    batch->head = NULL;
01151    batch->tail = NULL;
01152 }

static void set_one_cid ( struct ast_cdr cdr,
struct ast_channel c 
) [static]

Definition at line 815 of file cdr.c.

References ast_cdr_setvar(), ast_copy_string(), ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_cdr::clid, num, S_OR, and ast_cdr::src.

Referenced by ast_cdr_init(), ast_cdr_setcid(), and ast_cdr_update().

00816 {
00817    /* Grab source from ANI or normal Caller*ID */
00818    const char *num = S_OR(c->cid.cid_ani, c->cid.cid_num);
00819    if (!cdr)
00820       return;
00821    if (!ast_strlen_zero(c->cid.cid_name)) {
00822       if (!ast_strlen_zero(num)) /* both name and number */
00823          snprintf(cdr->clid, sizeof(cdr->clid), "\"%s\" <%s>", c->cid.cid_name, num);
00824       else           /* only name */
00825          ast_copy_string(cdr->clid, c->cid.cid_name, sizeof(cdr->clid));
00826    } else if (!ast_strlen_zero(num)) { /* only number */
00827       ast_copy_string(cdr->clid, num, sizeof(cdr->clid));
00828    } else {          /* nothing known */
00829       cdr->clid[0] = '\0';
00830    }
00831    ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src));
00832    ast_cdr_setvar(cdr, "dnid", S_OR(c->cid.cid_dnid, ""), 0);
00833 
00834 }

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

Definition at line 1213 of file cdr.c.

References ast_cdr_submit_batch(), ast_sched_add(), batchtime, and cdr_sched.

Referenced by do_reload(), and submit_unscheduled_batch().

01214 {
01215    ast_cdr_submit_batch(0);
01216    /* manually reschedule from this point in time */
01217    cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01218    /* returning zero so the scheduler does not automatically reschedule */
01219    return 0;
01220 }

static void submit_unscheduled_batch ( void   )  [static]

Definition at line 1222 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, and submit_scheduled_batch().

Referenced by ast_cdr_detach(), and handle_cli_submit().

01223 {
01224    /* this is okay since we are not being called from within the scheduler */
01225    AST_SCHED_DEL(sched, cdr_sched);
01226    /* schedule the submission to occur ASAP (1 ms) */
01227    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
01228    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
01229    ast_mutex_lock(&cdr_pending_lock);
01230    ast_cond_signal(&cdr_pending_cond);
01231    ast_mutex_unlock(&cdr_pending_lock);
01232 }


Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]

Definition at line 55 of file cdr.c.

Referenced by __ast_channel_alloc_ap().

int ast_default_amaflags = AST_CDR_DOCUMENTATION

Default AMA flag for billing records (CDR's)

Definition at line 54 of file cdr.c.

Referenced by __ast_channel_alloc_ap(), and ast_bridge_call().

struct ast_cdr_batch * batch [static]
int batchmode [static]

Definition at line 88 of file cdr.c.

Referenced by ast_cdr_detach(), do_reload(), and handle_cli_status().

int batchsafeshutdown [static]

Definition at line 92 of file cdr.c.

Referenced by ast_cdr_engine_term(), do_reload(), and handle_cli_status().

int batchscheduleronly [static]

Definition at line 91 of file cdr.c.

Referenced by ast_cdr_submit_batch(), do_reload(), and handle_cli_status().

int batchsize [static]

Definition at line 89 of file cdr.c.

Referenced by ast_cdr_detach(), do_reload(), and handle_cli_status().

int batchtime [static]

Definition at line 90 of file cdr.c.

Referenced by do_reload(), handle_cli_status(), and submit_scheduled_batch().

ast_mutex_t cdr_batch_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]

Definition at line 94 of file cdr.c.

Referenced by ast_cdr_detach(), ast_cdr_engine_init(), ast_cdr_submit_batch(), and do_reload().

Definition at line 98 of file cdr.c.

Referenced by do_cdr(), do_reload(), and submit_unscheduled_batch().

ast_mutex_t cdr_pending_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]

Definition at line 97 of file cdr.c.

Referenced by do_cdr(), and submit_unscheduled_batch().

const char* cdr_readonly_vars[] [static]
Initial value:
 { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
                "lastapp", "lastdata", "start", "answer", "end", "duration",
                "billsec", "disposition", "amaflags", "accountcode", "uniqueid",
                "userfield", NULL }

Definition at line 285 of file cdr.c.

Referenced by ast_cdr_serialize_variables(), and ast_cdr_setvar().

int cdr_sched = -1 [static]
pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 79 of file cdr.c.

Referenced by do_reload().

struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CDR status") [static]

Definition at line 1394 of file cdr.c.

Referenced by ast_cdr_engine_init().

struct ast_cli_entry cli_submit = AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data") [static]

Definition at line 1393 of file cdr.c.

Referenced by do_reload().

int enabled [static]
struct sched_context* sched [static]

Definition at line 77 of file cdr.c.

int unanswered [static]

Is the CDR subsystem enabled ?

Definition at line 87 of file cdr.c.

Referenced by ast_cdr_isset_unanswered(), do_reload(), handle_cli_status(), and post_cdr().


Generated by  doxygen 1.6.2