Mon Mar 31 07:39:15 2008

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

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

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

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

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

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

Referenced by __ast_read(), and ast_answer().

00696 {
00697 
00698    for (; cdr; cdr = cdr->next) {
00699       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00700          check_post(cdr);
00701          if (cdr->disposition < AST_CDR_ANSWERED)
00702             cdr->disposition = AST_CDR_ANSWERED;
00703          if (ast_tvzero(cdr->answer))
00704             cdr->answer = ast_tvnow();
00705       }
00706    }
00707 }

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

Definition at line 1044 of file cdr.c.

References ast_cdr::next.

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

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

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

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

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

void ast_cdr_busy ( struct ast_cdr cdr  ) 

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

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

00710 {
00711 
00712    for (; cdr; cdr = cdr->next) {
00713       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00714          check_post(cdr);
00715          if (cdr->disposition < AST_CDR_BUSY)
00716             cdr->disposition = AST_CDR_BUSY;
00717       }
00718    }
00719 }

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

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

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

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

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

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

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

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

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

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

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

References AST_CAUSE_BUSY, AST_CAUSE_NORMAL, ast_cdr_busy(), 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().

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

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

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  ) 

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

References ast_cdr::answer, AST_CDR_FAILED, AST_CDR_FLAG_LOCKED, ast_log(), ast_test_flag, ast_cdr::billsec, check_post(), 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().

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

int ast_cdr_engine_init ( void   ) 

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

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

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

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1442 of file cdr.c.

References do_reload().

01443 {
01444    return do_reload();
01445 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1437 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01438 {
01439    ast_cdr_submit_batch(batchsafeshutdown);
01440 }

void ast_cdr_failed ( struct ast_cdr cdr  ) 

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

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

00722 {
00723    for (; cdr; cdr = cdr->next) {
00724       check_post(cdr);
00725       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00726          if (cdr->disposition < AST_CDR_FAILED)
00727             cdr->disposition = AST_CDR_FAILED;
00728       }
00729    }
00730 }

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

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

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

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

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

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

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

Definition at line 820 of file cdr.c.

References ast_channel::_state, ast_channel::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NULL, AST_STATE_UP, ast_test_flag, ast_cdr::channel, ast_channel::context, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_cdr::next, S_OR, and set_one_cid().

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

00821 {
00822    char *chan;
00823 
00824    for ( ; cdr ; cdr = cdr->next) {
00825       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00826          chan = S_OR(cdr->channel, "<unknown>");
00827          ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
00828          set_one_cid(cdr, c);
00829 
00830          cdr->disposition = (c->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
00831          cdr->amaflags = c->amaflags ? c->amaflags :  ast_default_amaflags;
00832          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00833          /* Destination information */
00834          ast_copy_string(cdr->dst, S_OR(c->macroexten,c->exten), sizeof(cdr->dst));
00835          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext,c->context), sizeof(cdr->dcontext));
00836          /* Unique call identifier */
00837          ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid));
00838       }
00839    }
00840    return 0;
00841 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Referenced by __ast_request_and_dial(), ast_feature_request_and_dial(), builtin_blindtransfer(), clear_caller(), findmeexec(), and pbx_exec().

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

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

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

Referenced by ast_set_callerid().

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

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

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

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

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

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

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

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

00294 {
00295    struct ast_var_t *newvariable;
00296    struct varshead *headp;
00297    int x;
00298    
00299    if (!cdr)  /* don't die if the cdr is null */
00300       return -1;
00301    
00302    for(x = 0; cdr_readonly_vars[x]; x++) {
00303       if (!strcasecmp(name, cdr_readonly_vars[x])) {
00304          ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!.\n", name);
00305          return -1;
00306       }
00307    }
00308 
00309    if (!cdr) {
00310       ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n");
00311       return -1;
00312    }
00313 
00314    for (; cdr; cdr = recur ? cdr->next : NULL) {
00315       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
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(headp, 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 
00334    return 0;
00335 }

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

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

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

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

void ast_cdr_unregister ( const char *  name  ) 

unregister a CDR driver

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

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

int ast_cdr_update ( struct ast_channel c  ) 

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

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

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

References ast_localtime(), and t.

Referenced by ast_cdr_getvar().

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

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

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

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

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_setapp(), ast_cdr_setdestchan(), 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 1081 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().

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

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

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

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

static int do_reload ( void   )  [static]

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

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

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

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

Definition at line 1238 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, RESULT_SHOWUSAGE, and unanswered.

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

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

Definition at line 1273 of file cdr.c.

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

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

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1070 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

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

static void post_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 978 of file cdr.c.

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

Referenced by ast_cdr_detach(), and do_batch_backend_process().

00979 {
00980    char *chan;
00981    struct ast_cdr_beitem *i;
00982 
00983    for ( ; cdr ; cdr = cdr->next) {
00984       if (!unanswered && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
00985          /* For people, who don't want to see unanswered single-channel events */
00986          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
00987          continue;
00988       }
00989 
00990       chan = S_OR(cdr->channel, "<unknown>");
00991       check_post(cdr);
00992       if (ast_tvzero(cdr->end))
00993          ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan);
00994       if (ast_tvzero(cdr->start))
00995          ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
00996       ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
00997       if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
00998          continue;
00999       AST_LIST_LOCK(&be_list);
01000       AST_LIST_TRAVERSE(&be_list, i, list) {
01001          i->be(cdr);
01002       }
01003       AST_LIST_UNLOCK(&be_list);
01004    }
01005 }

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

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

01063 {
01064    batch->size = 0;
01065    batch->head = NULL;
01066    batch->tail = NULL;
01067 }

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

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

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

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

Definition at line 1134 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

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

static void submit_unscheduled_batch ( void   )  [static]

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

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


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]

Definition at line 93 of file cdr.c.

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

int batchsafeshutdown [static]

Definition at line 97 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 96 of file cdr.c.

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

int batchsize [static]

Definition at line 94 of file cdr.c.

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

int batchtime [static]

Definition at line 95 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 103 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 286 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 1291 of file cdr.c.

Referenced by ast_cdr_engine_init(), and dnsmgr_init().

struct ast_cli_entry cli_submit [static]

Definition at line 1284 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(), ack_trans(), ast_rtp_new(), ast_rtp_new_with_bindaddr(), ast_udptl_new(), ast_udptl_new_with_bindaddr(), auth_fail(), build_peer(), delete_users(), destroy_packet(), destroy_packets(), destroy_peer(), dnsmgr_init(), dnsmgr_start_refresh(), do_refresh(), do_register(), do_reload(), dundi_discover(), dundi_query(), dundi_send(), find_callno(), handle_command_response(), 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(), populate_addr(), precache_trans(), qualify_peer(), reg_source_db(), sched_thread(), schedule_delivery(), sip_alloc(), sip_call(), sip_cancel_destroy(), sip_destroy_peer(), sip_hangup(), sip_poke_all_peers(), sip_poke_noanswer(), sip_poke_peer(), sip_registry_destroy(), sip_scheddestroy(), sip_send_all_registers(), socket_process(), transmit_register(), unlink_peer(), unload_module(), update_jbsched(), and update_registry().

int unanswered [static]

Is the CDR subsystem enabled ?

Definition at line 92 of file cdr.c.

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


Generated on Mon Mar 31 07:39:16 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1