Fri Aug 24 02:23:27 2007

Asterisk developer's documentation


cdr.c File Reference

Call Detail Record API. More...

#include "asterisk.h"
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/logger.h"
#include "asterisk/callerid.h"
#include "asterisk/causes.h"
#include "asterisk/options.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

Defines

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

Functions

ast_cdrast_cdr_alloc (void)
 Allocate a CDR record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).
int ast_cdr_amaflags2int (const char *flag)
void ast_cdr_answer (struct ast_cdr *cdr)
ast_cdrast_cdr_append (struct ast_cdr *cdr, struct ast_cdr *newcdr)
int ast_cdr_appenduserfield (struct ast_channel *chan, const char *userfield)
void ast_cdr_busy (struct ast_cdr *cdr)
int ast_cdr_copy_vars (struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
void ast_cdr_detach (struct ast_cdr *cdr)
void ast_cdr_discard (struct ast_cdr *cdr)
 Discard and free a CDR record.
char * ast_cdr_disp2str (int disposition)
int ast_cdr_disposition (struct ast_cdr *cdr, int cause)
ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).
void ast_cdr_end (struct ast_cdr *cdr)
int ast_cdr_engine_init (void)
int ast_cdr_engine_reload (void)
void ast_cdr_engine_term (void)
void ast_cdr_failed (struct ast_cdr *cdr)
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.
void ast_cdr_merge (struct ast_cdr *to, struct ast_cdr *from)
void ast_cdr_noanswer (struct ast_cdr *cdr)
int ast_cdr_register (const char *name, const char *desc, ast_cdrbe be)
void ast_cdr_reset (struct ast_cdr *cdr, struct ast_flags *_flags)
int ast_cdr_serialize_variables (struct ast_cdr *cdr, char *buf, size_t size, char delim, char sep, int recur)
int ast_cdr_setaccount (struct ast_channel *chan, const char *account)
int ast_cdr_setamaflags (struct ast_channel *chan, const char *flag)
void ast_cdr_setapp (struct ast_cdr *cdr, char *app, char *data)
int ast_cdr_setcid (struct ast_cdr *cdr, struct ast_channel *c)
void ast_cdr_setdestchan (struct ast_cdr *cdr, const char *chann)
int ast_cdr_setuserfield (struct ast_channel *chan, const char *userfield)
int ast_cdr_setvar (struct ast_cdr *cdr, const char *name, const char *value, int recur)
void ast_cdr_start (struct ast_cdr *cdr)
void ast_cdr_submit_batch (int shutdown)
void ast_cdr_unregister (const char *name)
int ast_cdr_update (struct ast_channel *c)
static AST_LIST_HEAD_STATIC (be_list, ast_cdr_beitem)
 AST_MUTEX_DEFINE_STATIC (cdr_pending_lock)
 AST_MUTEX_DEFINE_STATIC (cdr_batch_lock)
static void cdr_get_tv (struct timeval tv, const char *fmt, char *buf, int bufsize)
static void cdr_merge_vars (struct ast_cdr *to, struct ast_cdr *from)
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 (void)
static int handle_cli_status (int fd, int argc, char *argv[])
static int handle_cli_submit (int fd, int argc, char *argv[])
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 (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_cond_t cdr_pending_cond
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
static struct ast_cli_entry cli_submit
static int enabled
static struct sched_contextsched


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

Referenced by do_reload().

#define BATCH_SCHEDULER_ONLY_DEFAULT   0

Definition at line 88 of file cdr.c.

Referenced by do_reload().

#define BATCH_SIZE_DEFAULT   100

Definition at line 86 of file cdr.c.

Referenced by do_reload().

#define BATCH_TIME_DEFAULT   300

Definition at line 87 of file cdr.c.

Referenced by do_reload().


Function Documentation

struct ast_cdr* ast_cdr_alloc ( void   ) 

Allocate a CDR record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).

Definition at line 456 of file cdr.c.

References ast_calloc, ast_log(), and LOG_ERROR.

Referenced by __agent_start_monitoring(), __ast_pbx_run(), __ast_read(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_dup(), ast_feature_request_and_dial(), ast_pbx_outgoing_app(), builtin_blindtransfer(), clear_caller(), findmeexec(), and start_monitor_exec().

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

int ast_cdr_amaflags2int ( const char *  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 968 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(), process_zap(), and set_config().

00969 {
00970    if (!strcasecmp(flag, "default"))
00971       return 0;
00972    if (!strcasecmp(flag, "omit"))
00973       return AST_CDR_OMIT;
00974    if (!strcasecmp(flag, "billing"))
00975       return AST_CDR_BILLING;
00976    if (!strcasecmp(flag, "documentation"))
00977       return AST_CDR_DOCUMENTATION;
00978    return -1;
00979 }

void ast_cdr_answer ( struct ast_cdr cdr  ) 

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

Definition at line 692 of file cdr.c.

References ast_cdr::answer, AST_CDR_ANSWERED, check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by __ast_read(), and ast_answer().

00693 {
00694 
00695    for (; cdr; cdr = cdr->next) {
00696       check_post(cdr);
00697       if (cdr->disposition < AST_CDR_ANSWERED)
00698          cdr->disposition = AST_CDR_ANSWERED;
00699       if (ast_tvzero(cdr->answer))
00700          cdr->answer = ast_tvnow();
00701    }
00702 }

struct ast_cdr* ast_cdr_append ( struct ast_cdr cdr,
struct ast_cdr newcdr 
)

Definition at line 1041 of file cdr.c.

References ast_cdr::next.

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

01042 {
01043    struct ast_cdr *ret;
01044 
01045    if (cdr) {
01046       ret = cdr;
01047 
01048       while (cdr->next)
01049          cdr = cdr->next;
01050       cdr->next = newcdr;
01051    } else {
01052       ret = newcdr;
01053    }
01054 
01055    return ret;
01056 }

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

Definition at line 934 of file cdr.c.

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

Referenced by action_setcdruserfield(), appendcdruserfield_exec(), and ast_bridge_call().

00935 {
00936    struct ast_cdr *cdr = chan->cdr;
00937 
00938    for ( ; cdr ; cdr = cdr->next) {
00939       int len = strlen(cdr->userfield);
00940 
00941       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00942          ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
00943    }
00944 
00945    return 0;
00946 }

void ast_cdr_busy ( struct ast_cdr cdr  ) 

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

Definition at line 704 of file cdr.c.

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

Referenced by ast_cdr_disposition(), and ring_entry().

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

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

Definition at line 334 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().

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

void ast_cdr_detach ( struct ast_cdr cdr  ) 

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

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

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

01154 {
01155    struct ast_cdr_batch_item *newtail;
01156    int curr;
01157 
01158    if (!cdr)
01159       return;
01160 
01161    /* maybe they disabled CDR stuff completely, so just drop it */
01162    if (!enabled) {
01163       if (option_debug)
01164          ast_log(LOG_DEBUG, "Dropping CDR !\n");
01165       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01166       ast_cdr_free(cdr);
01167       return;
01168    }
01169 
01170    /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
01171    if (!batchmode) {
01172       post_cdr(cdr);
01173       ast_cdr_free(cdr);
01174       return;
01175    }
01176 
01177    /* otherwise, each CDR gets put into a batch list (at the end) */
01178    if (option_debug)
01179       ast_log(LOG_DEBUG, "CDR detaching from this thread\n");
01180 
01181    /* we'll need a new tail for every CDR */
01182    if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
01183       post_cdr(cdr);
01184       ast_cdr_free(cdr);
01185       return;
01186    }
01187 
01188    /* don't traverse a whole list (just keep track of the tail) */
01189    ast_mutex_lock(&cdr_batch_lock);
01190    if (!batch)
01191       init_batch();
01192    if (!batch->head) {
01193       /* new batch is empty, so point the head at the new tail */
01194       batch->head = newtail;
01195    } else {
01196       /* already got a batch with something in it, so just append a new tail */
01197       batch->tail->next = newtail;
01198    }
01199    newtail->cdr = cdr;
01200    batch->tail = newtail;
01201    curr = batch->size++;
01202    ast_mutex_unlock(&cdr_batch_lock);
01203 
01204    /* if we have enough stuff to post, then do it */
01205    if (curr >= (batchsize - 1))
01206       submit_unscheduled_batch();
01207 }

void ast_cdr_discard ( struct ast_cdr cdr  ) 

Discard and free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing -- same as free, but no checks or complaints

Definition at line 445 of file cdr.c.

References ast_cdr_free_vars(), free, and ast_cdr::next.

Referenced by ast_bridge_call(), and ast_cdr_merge().

00446 {
00447    while (cdr) {
00448       struct ast_cdr *next = cdr->next;
00449 
00450       ast_cdr_free_vars(cdr, 0);
00451       free(cdr);
00452       cdr = next;
00453    }
00454 }

char* ast_cdr_disp2str ( int  disposition  ) 

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 863 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(), manager_log(), mysql_log(), odbc_log(), pgsql_log(), and tds_log().

00864 {
00865    switch (disposition) {
00866    case AST_CDR_NULL:
00867       return "NO ANSWER"; /* by default, for backward compatibility */
00868    case AST_CDR_NOANSWER:
00869       return "NO ANSWER";
00870    case AST_CDR_FAILED:
00871       return "FAILED";     
00872    case AST_CDR_BUSY:
00873       return "BUSY";    
00874    case AST_CDR_ANSWERED:
00875       return "ANSWERED";
00876    }
00877    return "UNKNOWN";
00878 }

int ast_cdr_disposition ( struct ast_cdr cdr,
int  cause 
)

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

Definition at line 743 of file cdr.c.

References AST_CAUSE_BUSY, AST_CAUSE_FAILURE, AST_CAUSE_NORMAL, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION, AST_CAUSE_NOTDEFINED, ast_cdr_busy(), ast_cdr_failed(), ast_log(), LOG_WARNING, and ast_cdr::next.

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

00744 {
00745    int res = 0;
00746 
00747    for (; cdr; cdr = cdr->next) {
00748       switch(cause) {
00749       case AST_CAUSE_BUSY:
00750          ast_cdr_busy(cdr);
00751          break;
00752       case AST_CAUSE_FAILURE:
00753       case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
00754          ast_cdr_failed(cdr);
00755          break;
00756       case AST_CAUSE_NORMAL:
00757          break;
00758       case AST_CAUSE_NOTDEFINED:
00759          res = -1;
00760          break;
00761       default:
00762          res = -1;
00763          ast_log(LOG_WARNING, "Cause (%d) not handled\n", cause);
00764       }
00765    }
00766    return res;
00767 }

struct ast_cdr* ast_cdr_dup ( struct ast_cdr cdr  ) 

Duplicate a record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 167 of file cdr.c.

References ast_cdr_alloc(), and ast_cdr_copy_vars().

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

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

void ast_cdr_end ( struct ast_cdr cdr  ) 

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

References ast_cdr::answer, AST_CDR_FAILED, ast_log(), 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_read(), __ast_request_and_dial(), ast_cdr_reset(), ast_feature_request_and_dial(), ast_hangup(), ast_pbx_outgoing_cdr_failed(), clear_caller(), and findmeexec().

00849 {
00850    for ( ; cdr ; cdr = cdr->next) {
00851       check_post(cdr);
00852       if (ast_tvzero(cdr->end))
00853          cdr->end = ast_tvnow();
00854       if (ast_tvzero(cdr->start)) {
00855          ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
00856          cdr->disposition = AST_CDR_FAILED;
00857       } else
00858          cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
00859       cdr->billsec = ast_tvzero(cdr->answer) ? 0 : cdr->end.tv_sec - cdr->answer.tv_sec;
00860    }
00861 }

int ast_cdr_engine_init ( void   ) 

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

Definition at line 1407 of file cdr.c.

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

Referenced by main().

01408 {
01409    int res;
01410 
01411    sched = sched_context_create();
01412    if (!sched) {
01413       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
01414       return -1;
01415    }
01416 
01417    ast_cli_register(&cli_status);
01418 
01419    res = do_reload();
01420    if (res) {
01421       ast_mutex_lock(&cdr_batch_lock);
01422       res = init_batch();
01423       ast_mutex_unlock(&cdr_batch_lock);
01424    }
01425 
01426    return res;
01427 }

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1436 of file cdr.c.

References do_reload().

01437 {
01438    return do_reload();
01439 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1431 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01432 {
01433    ast_cdr_submit_batch(batchsafeshutdown);
01434 }

void ast_cdr_failed ( struct ast_cdr cdr  ) 

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

Definition at line 716 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_cdr_disposition(), ast_feature_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten(), clear_caller(), and findmeexec().

00717 {
00718    for (; cdr; cdr = cdr->next) {
00719       check_post(cdr);
00720       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
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 881 of file cdr.c.

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

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

00882 {
00883    switch(flag) {
00884    case AST_CDR_OMIT:
00885       return "OMIT";
00886    case AST_CDR_BILLING:
00887       return "BILLING";
00888    case AST_CDR_DOCUMENTATION:
00889       return "DOCUMENTATION";
00890    }
00891    return "Unknown";
00892 }

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

Definition at line 425 of file cdr.c.

References AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, ast_cdr_free_vars(), ast_log(), ast_test_flag, ast_cdr::channel, ast_cdr::end, free, LOG_NOTICE, ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

00426 {
00427 
00428    while (cdr) {
00429       struct ast_cdr *next = cdr->next;
00430       char *chan = S_OR(cdr->channel, "<unknown>");
00431       if (!ast_test_flag(cdr, AST_CDR_FLAG_POSTED) && !ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
00432          ast_log(LOG_NOTICE, "CDR on channel '%s' not posted\n", chan);
00433       if (ast_tvzero(cdr->end))
00434          ast_log(LOG_NOTICE, "CDR on channel '%s' lacks end\n", chan);
00435       if (ast_tvzero(cdr->start))
00436          ast_log(LOG_NOTICE, "CDR on channel '%s' lacks start\n", chan);
00437 
00438       ast_cdr_free_vars(cdr, 0);
00439       free(cdr);
00440       cdr = next;
00441    }
00442 }

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

Definition at line 404 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().

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

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_strlen_zero(), 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, fmt, 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(), and cdr_read().

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);
00255    else if (!strcasecmp(name, "billsec"))
00256       snprintf(workspace, workspacelen, "%ld", cdr->billsec);
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 186 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().

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

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 Return is negligible. (returns 0 by default)

Definition at line 823 of file cdr.c.

References ast_channel::_state, ast_cdr::accountcode, ast_cdr::amaflags, ast_channel::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NULL, ast_log(), AST_STATE_UP, ast_strlen_zero(), ast_test_flag, ast_cdr::channel, ast_channel::context, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_channel::exten, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_cdr::next, S_OR, set_one_cid(), and ast_cdr::uniqueid.

Referenced by __ast_pbx_run(), __ast_read(), __ast_request_and_dial(), ast_bridge_call(), ast_feature_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

00824 {
00825    char *chan;
00826 
00827    for ( ; cdr ; cdr = cdr->next) {
00828       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00829          chan = S_OR(cdr->channel, "<unknown>");
00830          if (!ast_strlen_zero(cdr->channel)) 
00831             ast_log(LOG_WARNING, "CDR already initialized on '%s'\n", chan); 
00832          ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
00833          set_one_cid(cdr, c);
00834 
00835          cdr->disposition = (c->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
00836          cdr->amaflags = c->amaflags ? c->amaflags :  ast_default_amaflags;
00837          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00838          /* Destination information */
00839          ast_copy_string(cdr->dst, S_OR(c->macroexten,c->exten), sizeof(cdr->dst));
00840          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext,c->context), sizeof(cdr->dcontext));
00841          /* Unique call identifier */
00842          ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid));
00843       }
00844    }
00845    return 0;
00846 }

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 500 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_log(), ast_set_flag, ast_strlen_zero(), ast_test_flag, 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.

Referenced by ast_bridge_call().

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

void ast_cdr_noanswer ( struct ast_cdr cdr  ) 

Parameters:
cdr the cdr you wish to associate with the call Marks the channel disposition as "NO ANSWER"

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, ast_cdr::channel, ast_cdr::disposition, LOG_WARNING, and ast_cdr::next.

Referenced by wait_for_answer().

00728 {
00729    char *chan; 
00730 
00731    while (cdr) {
00732       chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
00733       if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
00734          ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
00735       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
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 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_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), LOG_WARNING, and ast_cdr_beitem::name.

Referenced by load_module(), my_load_module(), odbc_load_module(), process_my_load_module(), and tds_load_module().

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

void ast_cdr_reset ( struct ast_cdr cdr,
struct ast_flags 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 1004 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_POSTED, ast_cdr_free_vars(), 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, ast_flags::flags, ast_cdr::next, and ast_cdr::start.

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

01005 {
01006    struct ast_cdr *dup;
01007    struct ast_flags flags = { 0 };
01008 
01009    if (_flags)
01010       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
01011 
01012    for ( ; cdr ; cdr = cdr->next) {
01013       /* Detach if post is requested */
01014       if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01015          if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
01016             ast_cdr_end(cdr);
01017             if ((dup = ast_cdr_dup(cdr))) {
01018                ast_cdr_detach(dup);
01019             }
01020             ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
01021          }
01022 
01023          /* clear variables */
01024          if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
01025             ast_cdr_free_vars(cdr, 0);
01026          }
01027 
01028          /* Reset to initial state */
01029          ast_clear_flag(cdr, AST_FLAGS_ALL); 
01030          memset(&cdr->start, 0, sizeof(cdr->start));
01031          memset(&cdr->end, 0, sizeof(cdr->end));
01032          memset(&cdr->answer, 0, sizeof(cdr->answer));
01033          cdr->billsec = 0;
01034          cdr->duration = 0;
01035          ast_cdr_start(cdr);
01036          cdr->disposition = AST_CDR_NULL;
01037       }
01038    }
01039 }

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

Definition at line 360 of file cdr.c.

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

Referenced by handle_showchan(), and handle_showchan_deprecated().

00361 {
00362    struct ast_var_t *variables;
00363    const char *var, *val;
00364    char *tmp;
00365    char workspace[256];
00366    int total = 0, x = 0, i;
00367 
00368    memset(buf, 0, size);
00369 
00370    for (; cdr; cdr = recur ? cdr->next : NULL) {
00371       if (++x > 1)
00372          ast_build_string(&buf, &size, "\n");
00373 
00374       AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
00375          if (variables &&
00376              (var = ast_var_name(variables)) && (val = ast_var_value(variables)) &&
00377              !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
00378             if (ast_build_string(&buf, &size, "level %d: %s%c%s%c", x, var, delim, val, sep)) {
00379                ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
00380                break;
00381             } else
00382                total++;
00383          } else 
00384             break;
00385       }
00386 
00387       for (i = 0; cdr_readonly_vars[i]; i++) {
00388          ast_cdr_getvar(cdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
00389          if (!tmp)
00390             continue;
00391          
00392          if (ast_build_string(&buf, &size, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, tmp, sep)) {
00393             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
00394             break;
00395          } else
00396             total++;
00397       }
00398    }
00399 
00400    return total;
00401 }

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

Definition at line 894 of file cdr.c.

References accountcode, ast_cdr::accountcode, AST_CDR_FLAG_LOCKED, ast_string_field_set, ast_test_flag, ast_channel::cdr, and ast_cdr::next.

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

00895 {
00896    struct ast_cdr *cdr = chan->cdr;
00897 
00898    ast_string_field_set(chan, accountcode, account);
00899    for ( ; cdr ; cdr = cdr->next) {
00900       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00901          ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode));
00902       }
00903    }
00904    return 0;
00905 }

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

Definition at line 907 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().

00908 {
00909    struct ast_cdr *cdr;
00910    int newflag = ast_cdr_amaflags2int(flag);
00911    if (newflag) {
00912       for (cdr = chan->cdr; cdr; cdr = cdr->next) {
00913          if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00914             cdr->amaflags = newflag;
00915          }
00916       }
00917    }
00918 
00919    return 0;
00920 }

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

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_test_flag, check_post(), and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_feature_request_and_dial(), builtin_blindtransfer(), 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          if (!app)
00785             app = "";
00786          ast_copy_string(cdr->lastapp, app, sizeof(cdr->lastapp));
00787          if (!data)
00788             data = "";
00789          ast_copy_string(cdr->lastdata, data, sizeof(cdr->lastdata));
00790       }
00791    }
00792 }

int ast_cdr_setcid ( struct ast_cdr cdr,
struct ast_channel chan 
)

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 Return is negligible. (returns 0 by default)

Definition at line 814 of file cdr.c.

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

Referenced by ast_set_callerid().

00815 {
00816    for (; cdr; cdr = cdr->next) {
00817       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00818          set_one_cid(cdr, c);
00819    }
00820    return 0;
00821 }

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

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

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

Referenced by ast_bridge_call(), ast_bridge_call_thread(), builtin_blindtransfer(), park_exec(), and try_calling().

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

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

Definition at line 922 of file cdr.c.

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

Referenced by __agent_start_monitoring(), action_setcdruserfield(), ast_bridge_call(), cdr_write(), handle_request_info(), setcdruserfield_exec(), and start_monitor_exec().

00923 {
00924    struct ast_cdr *cdr = chan->cdr;
00925 
00926    for ( ; cdr ; cdr = cdr->next) {
00927       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 
00928          ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
00929    }
00930 
00931    return 0;
00932 }

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_LIST_INSERT_HEAD, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_var_assign(), ast_var_delete(), ast_var_name(), cdr_readonly_vars, LOG_ERROR, ast_cdr::next, and ast_cdr::varshead.

Referenced by cdr_write().

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       headp = &cdr->varshead;
00315       AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
00316          if (!strcasecmp(ast_var_name(newvariable), name)) {
00317             /* there is already such a variable, delete it */
00318             AST_LIST_REMOVE_CURRENT(headp, entries);
00319             ast_var_delete(newvariable);
00320             break;
00321          }
00322       }
00323       AST_LIST_TRAVERSE_SAFE_END;
00324 
00325       if (value) {
00326          newvariable = ast_var_assign(name, value);
00327          AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00328       }
00329    }
00330 
00331    return 0;
00332 }

void ast_cdr_start ( struct ast_cdr cdr  ) 

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

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

Referenced by __ast_pbx_run(), __ast_read(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_reset(), ast_feature_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

00680 {
00681    char *chan; 
00682 
00683    for (; cdr; cdr = cdr->next) {
00684       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00685          chan = S_OR(cdr->channel, "<unknown>");
00686          check_post(cdr);
00687          cdr->start = ast_tvnow();
00688       }
00689    }
00690 }

void ast_cdr_submit_batch ( int  shutdown  ) 

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

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, batch, batchscheduleronly, do_batch_backend_process(), ast_cdr_batch::head, LOG_DEBUG, LOG_WARNING, option_debug, and reset_batch().

Referenced by ast_cdr_engine_term(), and submit_scheduled_batch().

01096 {
01097    struct ast_cdr_batch_item *oldbatchitems = NULL;
01098    pthread_attr_t attr;
01099    pthread_t batch_post_thread = AST_PTHREADT_NULL;
01100 
01101    /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
01102    if (!batch || !batch->head)
01103       return;
01104 
01105    /* move the old CDRs aside, and prepare a new CDR batch */
01106    ast_mutex_lock(&cdr_batch_lock);
01107    oldbatchitems = batch->head;
01108    reset_batch();
01109    ast_mutex_unlock(&cdr_batch_lock);
01110 
01111    /* if configured, spawn a new thread to post these CDRs,
01112       also try to save as much as possible if we are shutting down safely */
01113    if (batchscheduleronly || shutdown) {
01114       if (option_debug)
01115          ast_log(LOG_DEBUG, "CDR single-threaded batch processing begins now\n");
01116       do_batch_backend_process(oldbatchitems);
01117    } else {
01118       pthread_attr_init(&attr);
01119       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01120       if (ast_pthread_create_background(&batch_post_thread, &attr, do_batch_backend_process, oldbatchitems)) {
01121          ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
01122          do_batch_backend_process(oldbatchitems);
01123       } else {
01124          if (option_debug)
01125             ast_log(LOG_DEBUG, "CDR multi-threaded batch processing begins now\n");
01126       }
01127       pthread_attr_destroy(&attr);
01128    }
01129 }

void ast_cdr_unregister ( const char *  name  ) 

unregister a CDR driver

Definition at line 146 of file cdr.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_verbose(), free, ast_cdr_beitem::name, option_verbose, and VERBOSE_PREFIX_2.

Referenced by my_unload_module(), odbc_unload_module(), tds_unload_module(), and unload_module().

00147 {
00148    struct ast_cdr_beitem *i = NULL;
00149 
00150    AST_LIST_LOCK(&be_list);
00151    AST_LIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
00152       if (!strcasecmp(name, i->name)) {
00153          AST_LIST_REMOVE_CURRENT(&be_list, list);
00154          if (option_verbose > 1)
00155             ast_verbose(VERBOSE_PREFIX_2 "Unregistered '%s' CDR backend\n", name);
00156          free(i);
00157          break;
00158       }
00159    }
00160    AST_LIST_TRAVERSE_SAFE_END;
00161    AST_LIST_UNLOCK(&be_list);
00162 }

int ast_cdr_update ( struct ast_channel c  ) 

Definition at line 948 of file cdr.c.

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

Referenced by __ast_request_and_dial(), ast_feature_request_and_dial(), ast_parseable_goto(), cb_events(), clear_caller(), and findmeexec().

00949 {
00950    struct ast_cdr *cdr = c->cdr;
00951 
00952    for ( ; cdr ; cdr = cdr->next) {
00953       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00954          set_one_cid(cdr, c);
00955 
00956          /* Copy account code et-al */ 
00957          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00958          
00959          /* Destination information */ /* XXX privilege macro* ? */
00960          ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst));
00961          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext));
00962       }
00963    }
00964 
00965    return 0;
00966 }

static AST_LIST_HEAD_STATIC ( be_list  ,
ast_cdr_beitem   
) [static]

AST_MUTEX_DEFINE_STATIC ( cdr_pending_lock   ) 

AST_MUTEX_DEFINE_STATIC ( cdr_batch_lock   ) 

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

Definition at line 203 of file cdr.c.

References ast_localtime(), and t.

Referenced by ast_cdr_getvar().

00204 {
00205    if (fmt == NULL) {   /* raw mode */
00206       snprintf(buf, bufsize, "%ld.%06ld", (long)tv.tv_sec, (long)tv.tv_usec);
00207    } else {  
00208       time_t t = tv.tv_sec;
00209       if (t) {
00210          struct tm tm;
00211 
00212          ast_localtime(&t, &tm, NULL);
00213          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 464 of file cdr.c.

References AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_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().

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

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

Definition at line 417 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_setapp(), ast_cdr_setdestchan(), ast_cdr_start(), and post_cdr().

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

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

Definition at line 1078 of file cdr.c.

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

Referenced by ast_cdr_submit_batch().

01079 {
01080    struct ast_cdr_batch_item *processeditem;
01081    struct ast_cdr_batch_item *batchitem = data;
01082 
01083    /* Push each CDR into storage mechanism(s) and free all the memory */
01084    while (batchitem) {
01085       post_cdr(batchitem->cdr);
01086       ast_cdr_free(batchitem->cdr);
01087       processeditem = batchitem;
01088       batchitem = batchitem->next;
01089       free(processeditem);
01090    }
01091 
01092    return NULL;
01093 }

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

Definition at line 1209 of file cdr.c.

References ast_cond_timedwait(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_runq(), ast_sched_wait(), ast_tvadd(), cdr_pending_cond, LOG_DEBUG, and option_debug.

Referenced by do_reload().

01210 {
01211    struct timespec timeout;
01212    int schedms;
01213    int numevents = 0;
01214 
01215    for(;;) {
01216       struct timeval now;
01217       schedms = ast_sched_wait(sched);
01218       /* this shouldn't happen, but provide a 1 second default just in case */
01219       if (schedms <= 0)
01220          schedms = 1000;
01221       now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
01222       timeout.tv_sec = now.tv_sec;
01223       timeout.tv_nsec = now.tv_usec * 1000;
01224       /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
01225       ast_mutex_lock(&cdr_pending_lock);
01226       ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
01227       numevents = ast_sched_runq(sched);
01228       ast_mutex_unlock(&cdr_pending_lock);
01229       if (option_debug > 1)
01230          ast_log(LOG_DEBUG, "Processed %d scheduled CDR batches from the run queue\n", numevents);
01231    }
01232 
01233    return NULL;
01234 }

static int do_reload ( void   )  [static]

Definition at line 1295 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_load(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN, 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_pending_cond, cdr_sched, cdr_thread, cli_submit, config, do_cdr(), enabled, LOG_ERROR, LOG_NOTICE, LOG_WARNING, and submit_scheduled_batch().

Referenced by ast_cdr_engine_init(), ast_cdr_engine_reload(), dnsmgr_init(), dnsmgr_reload(), and handle_cli_reload().

01296 {
01297    struct ast_config *config;
01298    const char *enabled_value;
01299    const char *batched_value;
01300    const char *scheduleronly_value;
01301    const char *batchsafeshutdown_value;
01302    const char *size_value;
01303    const char *time_value;
01304    const char *end_before_h_value;
01305    int cfg_size;
01306    int cfg_time;
01307    int was_enabled;
01308    int was_batchmode;
01309    int res=0;
01310 
01311    ast_mutex_lock(&cdr_batch_lock);
01312 
01313    batchsize = BATCH_SIZE_DEFAULT;
01314    batchtime = BATCH_TIME_DEFAULT;
01315    batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
01316    batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
01317    was_enabled = enabled;
01318    was_batchmode = batchmode;
01319    enabled = 1;
01320    batchmode = 0;
01321 
01322    /* don't run the next scheduled CDR posting while reloading */
01323    if (cdr_sched > -1)
01324       ast_sched_del(sched, cdr_sched);
01325 
01326    if ((config = ast_config_load("cdr.conf"))) {
01327       if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
01328          enabled = ast_true(enabled_value);
01329       }
01330       if ((batched_value = ast_variable_retrieve(config, "general", "batch"))) {
01331          batchmode = ast_true(batched_value);
01332       }
01333       if ((scheduleronly_value = ast_variable_retrieve(config, "general", "scheduleronly"))) {
01334          batchscheduleronly = ast_true(scheduleronly_value);
01335       }
01336       if ((batchsafeshutdown_value = ast_variable_retrieve(config, "general", "safeshutdown"))) {
01337          batchsafeshutdown = ast_true(batchsafeshutdown_value);
01338       }
01339       if ((size_value = ast_variable_retrieve(config, "general", "size"))) {
01340          if (sscanf(size_value, "%d", &cfg_size) < 1)
01341             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", size_value);
01342          else if (size_value < 0)
01343             ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
01344          else
01345             batchsize = cfg_size;
01346       }
01347       if ((time_value = ast_variable_retrieve(config, "general", "time"))) {
01348          if (sscanf(time_value, "%d", &cfg_time) < 1)
01349             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", time_value);
01350          else if (time_value < 0)
01351             ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
01352          else
01353             batchtime = cfg_time;
01354       }
01355       if ((end_before_h_value = ast_variable_retrieve(config, "general", "endbeforehexten")))
01356          ast_set2_flag(&ast_options, ast_true(end_before_h_value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
01357    }
01358 
01359    if (enabled && !batchmode) {
01360       ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
01361    } else if (enabled && batchmode) {
01362       cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01363       ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
01364    } else {
01365       ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
01366    }
01367 
01368    /* if this reload enabled the CDR batch mode, create the background thread
01369       if it does not exist */
01370    if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
01371       ast_cond_init(&cdr_pending_cond, NULL);
01372       if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
01373          ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
01374          ast_sched_del(sched, cdr_sched);
01375       } else {
01376          ast_cli_register(&cli_submit);
01377          ast_register_atexit(ast_cdr_engine_term);
01378          res = 0;
01379       }
01380    /* if this reload disabled the CDR and/or batch mode and there is a background thread,
01381       kill it */
01382    } else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
01383       /* wake up the thread so it will exit */
01384       pthread_cancel(cdr_thread);
01385       pthread_kill(cdr_thread, SIGURG);
01386       pthread_join(cdr_thread, NULL);
01387       cdr_thread = AST_PTHREADT_NULL;
01388       ast_cond_destroy(&cdr_pending_cond);
01389       ast_cli_unregister(&cli_submit);
01390       ast_unregister_atexit(ast_cdr_engine_term);
01391       res = 0;
01392       /* if leaving batch mode, then post the CDRs in the batch,
01393          and don't reschedule, since we are stopping CDR logging */
01394       if (!batchmode && was_batchmode) {
01395          ast_cdr_engine_term();
01396       }
01397    } else {
01398       res = 0;
01399    }
01400 
01401    ast_mutex_unlock(&cdr_batch_lock);
01402    ast_config_destroy(config);
01403 
01404    return res;
01405 }

static int handle_cli_status ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 1236 of file cdr.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_sched_when(), batch, batchmode, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_sched, enabled, ast_cdr_beitem::name, and RESULT_SHOWUSAGE.

01237 {
01238    struct ast_cdr_beitem *beitem=NULL;
01239    int cnt=0;
01240    long nextbatchtime=0;
01241 
01242    if (argc > 2)
01243       return RESULT_SHOWUSAGE;
01244 
01245    ast_cli(fd, "CDR logging: %s\n", enabled ? "enabled" : "disabled");
01246    ast_cli(fd, "CDR mode: %s\n", batchmode ? "batch" : "simple");
01247    if (enabled) {
01248       if (batchmode) {
01249          if (batch)
01250             cnt = batch->size;
01251          if (cdr_sched > -1)
01252             nextbatchtime = ast_sched_when(sched, cdr_sched);
01253          ast_cli(fd, "CDR safe shut down: %s\n", batchsafeshutdown ? "enabled" : "disabled");
01254          ast_cli(fd, "CDR batch threading model: %s\n", batchscheduleronly ? "scheduler only" : "scheduler plus separate threads");
01255          ast_cli(fd, "CDR current batch size: %d record%s\n", cnt, (cnt != 1) ? "s" : "");
01256          ast_cli(fd, "CDR maximum batch size: %d record%s\n", batchsize, (batchsize != 1) ? "s" : "");
01257          ast_cli(fd, "CDR maximum batch time: %d second%s\n", batchtime, (batchtime != 1) ? "s" : "");
01258          ast_cli(fd, "CDR next scheduled batch processing time: %ld second%s\n", nextbatchtime, (nextbatchtime != 1) ? "s" : "");
01259       }
01260       AST_LIST_LOCK(&be_list);
01261       AST_LIST_TRAVERSE(&be_list, beitem, list) {
01262          ast_cli(fd, "CDR registered backend: %s\n", beitem->name);
01263       }
01264       AST_LIST_UNLOCK(&be_list);
01265    }
01266 
01267    return 0;
01268 }

static int handle_cli_submit ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 1270 of file cdr.c.

References ast_cli(), RESULT_SHOWUSAGE, and submit_unscheduled_batch().

01271 {
01272    if (argc > 2)
01273       return RESULT_SHOWUSAGE;
01274 
01275    submit_unscheduled_batch();
01276    ast_cli(fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
01277 
01278    return 0;
01279 }

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1067 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

01068 {
01069    /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
01070    if (!(batch = ast_malloc(sizeof(*batch))))
01071       return -1;
01072 
01073    reset_batch();
01074 
01075    return 0;
01076 }

static void post_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 981 of file cdr.c.

References AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_set_flag, ast_test_flag, ast_cdr_beitem::be, ast_cdr::channel, check_post(), ast_cdr::end, LOG_WARNING, ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

00982 {
00983    char *chan;
00984    struct ast_cdr_beitem *i;
00985 
00986    for ( ; cdr ; cdr = cdr->next) {
00987       chan = S_OR(cdr->channel, "<unknown>");
00988       check_post(cdr);
00989       if (ast_tvzero(cdr->end))
00990          ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan);
00991       if (ast_tvzero(cdr->start))
00992          ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
00993       ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
00994       if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
00995          continue;
00996       AST_LIST_LOCK(&be_list);
00997       AST_LIST_TRAVERSE(&be_list, i, list) {
00998          i->be(cdr);
00999       }
01000       AST_LIST_UNLOCK(&be_list);
01001    }
01002 }

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1059 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().

01060 {
01061    batch->size = 0;
01062    batch->head = NULL;
01063    batch->tail = NULL;
01064 }

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

Definition at line 795 of file cdr.c.

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

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

00796 {
00797    /* Grab source from ANI or normal Caller*ID */
00798    const char *num = S_OR(c->cid.cid_ani, c->cid.cid_num);
00799    if (!cdr)
00800       return;
00801    if (!ast_strlen_zero(c->cid.cid_name)) {
00802       if (!ast_strlen_zero(num)) /* both name and number */
00803          snprintf(cdr->clid, sizeof(cdr->clid), "\"%s\" <%s>", c->cid.cid_name, num);
00804       else           /* only name */
00805          ast_copy_string(cdr->clid, c->cid.cid_name, sizeof(cdr->clid));
00806    } else if (!ast_strlen_zero(num)) { /* only number */
00807       ast_copy_string(cdr->clid, num, sizeof(cdr->clid));
00808    } else {          /* nothing known */
00809       cdr->clid[0] = '\0';
00810    }
00811    ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src));
00812 
00813 }

static int submit_scheduled_batch ( void *  data  )  [static]

Definition at line 1131 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

01132 {
01133    ast_cdr_submit_batch(0);
01134    /* manually reschedule from this point in time */
01135    cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01136    /* returning zero so the scheduler does not automatically reschedule */
01137    return 0;
01138 }

static void submit_unscheduled_batch ( void   )  [static]

Definition at line 1140 of file cdr.c.

References ast_cond_signal(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_add(), ast_sched_del(), cdr_pending_cond, cdr_sched, and submit_scheduled_batch().

Referenced by ast_cdr_detach(), and handle_cli_submit().

01141 {
01142    /* this is okay since we are not being called from within the scheduler */
01143    if (cdr_sched > -1)
01144       ast_sched_del(sched, cdr_sched);
01145    /* schedule the submission to occur ASAP (1 ms) */
01146    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
01147    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
01148    ast_mutex_lock(&cdr_pending_lock);
01149    ast_cond_signal(&cdr_pending_cond);
01150    ast_mutex_unlock(&cdr_pending_lock);
01151 }


Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]

Definition at line 60 of file cdr.c.

int ast_default_amaflags = AST_CDR_DOCUMENTATION

Default AMA flag for billing records (CDR's)

Definition at line 59 of file cdr.c.

struct ast_cdr_batch * batch [static]

Referenced by ast_cdr_detach(), ast_cdr_submit_batch(), handle_cli_status(), init_batch(), and reset_batch().

int batchmode [static]

Is the CDR subsystem enabled ?

Definition at line 92 of file cdr.c.

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

int batchsafeshutdown [static]

Definition at line 96 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 95 of file cdr.c.

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

int batchsize [static]

Definition at line 93 of file cdr.c.

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

int batchtime [static]

Definition at line 94 of file cdr.c.

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

ast_cond_t cdr_pending_cond [static]

Definition at line 102 of file cdr.c.

Referenced by do_cdr(), do_reload(), 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]

Definition at line 83 of file cdr.c.

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

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 84 of file cdr.c.

Referenced by do_reload().

struct ast_cli_entry cli_status [static]

Definition at line 1288 of file cdr.c.

Referenced by ast_cdr_engine_init(), and dnsmgr_init().

struct ast_cli_entry cli_submit [static]

Definition at line 1281 of file cdr.c.

Referenced by do_reload().

int enabled [static]

Definition at line 91 of file cdr.c.

Referenced by __ast_http_load(), ast_cdr_detach(), ast_dnsmgr_lookup(), do_reload(), handle_cli_status(), init_manager(), load_odbc_config(), osp_check_destination(), and reload().

struct sched_context* sched [static]

Definition at line 82 of file cdr.c.

Referenced by __attempt_transmit(), __iax2_poke_noanswer(), __oh323_destroy(), __oh323_rtp_create(), __oh323_update_info(), __send_lagrq(), __send_ping(), __sip_ack(), __sip_destroy(), __sip_reliable_xmit(), __sip_semi_ack(), __unload_module(), _sip_show_peer(), ast_rtp_new(), ast_rtp_new_with_bindaddr(), ast_udptl_new(), ast_udptl_new_with_bindaddr(), auth_fail(), build_peer(), delete_users(), dnsmgr_init(), dnsmgr_start_refresh(), do_refresh(), do_reload(), find_callno(), handle_response_invite(), handle_response_peerpoke(), handle_response_register(), iax2_ack_registry(), iax2_call(), iax2_destroy_helper(), iax2_do_register(), iax2_dprequest(), iax2_frame_free(), iax2_poke_peer(), iax2_provision(), load_module(), make_trunk(), network_thread(), parse_register_contact(), peer_destructor(), reg_source_db(), sched_thread(), schedule_delivery(), sip_alloc(), sip_call(), sip_cancel_destroy(), sip_destroy_peer(), sip_poke_all_peers(), sip_poke_noanswer(), sip_poke_peer(), sip_registry_destroy(), sip_scheddestroy(), sip_send_all_registers(), socket_process(), transmit_register(), unload_module(), update_jbsched(), and update_registry().


Generated on Fri Aug 24 02:23:28 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1