Mon May 14 04:45:07 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)
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 check_start (struct ast_cdr *cdr)
 print a warning if cdr already started
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 464 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(), ast_pbx_outgoing_exten(), builtin_blindtransfer(), clear_caller(), findmeexec(), and start_monitor_exec().

00465 {
00466    struct ast_cdr *x = ast_calloc(1, sizeof(struct ast_cdr));
00467    if (!x)
00468       ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
00469    return x;
00470 }

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

00894 {
00895    if (!strcasecmp(flag, "default"))
00896       return 0;
00897    if (!strcasecmp(flag, "omit"))
00898       return AST_CDR_OMIT;
00899    if (!strcasecmp(flag, "billing"))
00900       return AST_CDR_BILLING;
00901    if (!strcasecmp(flag, "documentation"))
00902       return AST_CDR_DOCUMENTATION;
00903    return -1;
00904 }

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

00639 {
00640 
00641    for (; cdr; cdr = cdr->next) {
00642       check_post(cdr);
00643       if (cdr->disposition < AST_CDR_ANSWERED)
00644          cdr->disposition = AST_CDR_ANSWERED;
00645       if (ast_tvzero(cdr->answer))
00646          cdr->answer = ast_tvnow();
00647    }
00648 }

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

Definition at line 966 of file cdr.c.

References ast_cdr::next.

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

00967 {
00968    struct ast_cdr *ret;
00969 
00970    if (cdr) {
00971       ret = cdr;
00972 
00973       while (cdr->next)
00974          cdr = cdr->next;
00975       cdr->next = newcdr;
00976    } else {
00977       ret = newcdr;
00978    }
00979 
00980    return ret;
00981 }

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

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

00859 {
00860    struct ast_cdr *cdr = chan->cdr;
00861 
00862    for ( ; cdr ; cdr = cdr->next) {
00863       int len = strlen(cdr->userfield);
00864 
00865       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00866          ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
00867    }
00868 
00869    return 0;
00870 }

void ast_cdr_busy ( struct ast_cdr cdr  ) 

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

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

00651 {
00652 
00653    for (; cdr; cdr = cdr->next) {
00654       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00655          check_post(cdr);
00656          if (cdr->disposition < AST_CDR_BUSY)
00657             cdr->disposition = AST_CDR_BUSY;
00658       }
00659    }
00660 }

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

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

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

01079 {
01080    struct ast_cdr_batch_item *newtail;
01081    int curr;
01082 
01083    if (!cdr)
01084       return;
01085 
01086    /* maybe they disabled CDR stuff completely, so just drop it */
01087    if (!enabled) {
01088       if (option_debug)
01089          ast_log(LOG_DEBUG, "Dropping CDR !\n");
01090       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01091       ast_cdr_free(cdr);
01092       return;
01093    }
01094 
01095    /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
01096    if (!batchmode) {
01097       post_cdr(cdr);
01098       ast_cdr_free(cdr);
01099       return;
01100    }
01101 
01102    /* otherwise, each CDR gets put into a batch list (at the end) */
01103    if (option_debug)
01104       ast_log(LOG_DEBUG, "CDR detaching from this thread\n");
01105 
01106    /* we'll need a new tail for every CDR */
01107    if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
01108       post_cdr(cdr);
01109       ast_cdr_free(cdr);
01110       return;
01111    }
01112 
01113    /* don't traverse a whole list (just keep track of the tail) */
01114    ast_mutex_lock(&cdr_batch_lock);
01115    if (!batch)
01116       init_batch();
01117    if (!batch->head) {
01118       /* new batch is empty, so point the head at the new tail */
01119       batch->head = newtail;
01120    } else {
01121       /* already got a batch with something in it, so just append a new tail */
01122       batch->tail->next = newtail;
01123    }
01124    newtail->cdr = cdr;
01125    batch->tail = newtail;
01126    curr = batch->size++;
01127    ast_mutex_unlock(&cdr_batch_lock);
01128 
01129    /* if we have enough stuff to post, then do it */
01130    if (curr >= (batchsize - 1))
01131       submit_unscheduled_batch();
01132 }

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

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

Referenced by ast_bridge_call().

00454 {
00455    while (cdr) {
00456       struct ast_cdr *next = cdr->next;
00457 
00458       ast_cdr_free_vars(cdr, 0);
00459       free(cdr);
00460       cdr = next;
00461    }
00462 }

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

References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_FAILED, and AST_CDR_NOANSWER.

Referenced by ast_cdr_getvar(), build_csv_record(), build_radius_record(), csv_log(), manager_log(), mysql_log(), odbc_log(), pgsql_log(), and tds_log().

00793 {
00794    switch (disposition) {
00795    case AST_CDR_NOANSWER:
00796       return "NO ANSWER";
00797    case AST_CDR_FAILED:
00798       return "FAILED";     
00799    case AST_CDR_BUSY:
00800       return "BUSY";    
00801    case AST_CDR_ANSWERED:
00802       return "ANSWERED";
00803    }
00804    return "UNKNOWN";
00805 }

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

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

00674 {
00675    int res = 0;
00676 
00677    for (; cdr; cdr = cdr->next) {
00678       switch(cause) {
00679       case AST_CAUSE_BUSY:
00680          ast_cdr_busy(cdr);
00681          break;
00682       case AST_CAUSE_FAILURE:
00683          ast_cdr_failed(cdr);
00684          break;
00685       case AST_CAUSE_NORMAL:
00686          break;
00687       case AST_CAUSE_NOTDEFINED:
00688          res = -1;
00689          break;
00690       default:
00691          res = -1;
00692          ast_log(LOG_WARNING, "Cause not handled\n");
00693       }
00694    }
00695    return res;
00696 }

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

00778 {
00779    for ( ; cdr ; cdr = cdr->next) {
00780       check_post(cdr);
00781       if (ast_tvzero(cdr->end))
00782          cdr->end = ast_tvnow();
00783       if (ast_tvzero(cdr->start)) {
00784          ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
00785          cdr->disposition = AST_CDR_FAILED;
00786       } else
00787          cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
00788       cdr->billsec = ast_tvzero(cdr->answer) ? 0 : cdr->end.tv_sec - cdr->answer.tv_sec;
00789    }
00790 }

int ast_cdr_engine_init ( void   ) 

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

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

01333 {
01334    int res;
01335 
01336    sched = sched_context_create();
01337    if (!sched) {
01338       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
01339       return -1;
01340    }
01341 
01342    ast_cli_register(&cli_status);
01343 
01344    res = do_reload();
01345    if (res) {
01346       ast_mutex_lock(&cdr_batch_lock);
01347       res = init_batch();
01348       ast_mutex_unlock(&cdr_batch_lock);
01349    }
01350 
01351    return res;
01352 }

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1361 of file cdr.c.

References do_reload().

01362 {
01363    return do_reload();
01364 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1356 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01357 {
01358    ast_cdr_submit_batch(batchsafeshutdown);
01359 }

void ast_cdr_failed ( struct ast_cdr cdr  ) 

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

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

00663 {
00664    for (; cdr; cdr = cdr->next) {
00665       check_post(cdr);
00666       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00667          if (cdr->disposition < AST_CDR_FAILED)
00668             cdr->disposition = AST_CDR_FAILED;
00669       }
00670    }
00671 }

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

00809 {
00810    switch(flag) {
00811    case AST_CDR_OMIT:
00812       return "OMIT";
00813    case AST_CDR_BILLING:
00814       return "BILLING";
00815    case AST_CDR_DOCUMENTATION:
00816       return "DOCUMENTATION";
00817    }
00818    return "Unknown";
00819 }

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

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

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

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

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

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

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

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 752 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_NOANSWER, 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_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(), ast_pbx_outgoing_exten(), builtin_blindtransfer(), clear_caller(), and findmeexec().

00753 {
00754    char *chan;
00755 
00756    for ( ; cdr ; cdr = cdr->next) {
00757       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00758          chan = S_OR(cdr->channel, "<unknown>");
00759          if (!ast_strlen_zero(cdr->channel)) 
00760             ast_log(LOG_WARNING, "CDR already initialized on '%s'\n", chan); 
00761          ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
00762          set_one_cid(cdr, c);
00763 
00764          cdr->disposition = (c->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
00765          cdr->amaflags = c->amaflags ? c->amaflags :  ast_default_amaflags;
00766          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00767          /* Destination information */
00768          ast_copy_string(cdr->dst, c->exten, sizeof(cdr->dst));
00769          ast_copy_string(cdr->dcontext, c->context, sizeof(cdr->dcontext));
00770          /* Unique call identifier */
00771          ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid));
00772       }
00773    }
00774    return 0;
00775 }

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

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_append(), 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_set_flag, ast_strlen_zero(), ast_test_flag, ast_cdr::billsec, cdr_merge_vars(), ast_cdr::channel, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::next, ast_cdr::src, ast_cdr::start, and ast_cdr::userfield.

Referenced by ast_bridge_call().

00509 {
00510    struct ast_cdr *tcdr;
00511    
00512    if (!to || !from)
00513       return;
00514    
00515    if (!ast_tvzero(from->start)) {
00516       if (!ast_tvzero(to->start)) {
00517          if (ast_tvcmp(to->start, from->start) > 0 ) {
00518             to->start = from->start; /* use the earliest time */
00519             from->start = ast_tv(0,0); /* we actively "steal" these values */
00520          }
00521          /* else nothing to do */
00522       } else {
00523          to->start = from->start;
00524          from->start = ast_tv(0,0); /* we actively "steal" these values */
00525       }
00526    }
00527    if (!ast_tvzero(from->answer)) {
00528       if (!ast_tvzero(to->answer)) {
00529          if (ast_tvcmp(to->answer, from->answer) > 0 ) {
00530             to->answer = from->answer; /* use the earliest time */
00531             from->answer = ast_tv(0,0); /* we actively "steal" these values */
00532          }
00533          /* we got the earliest answer time, so we'll settle for that? */
00534       } else {
00535          to->answer = from->answer;
00536          from->answer = ast_tv(0,0); /* we actively "steal" these values */
00537       }
00538    }
00539    if (!ast_tvzero(from->end)) {
00540       if (!ast_tvzero(to->end)) {
00541          if (ast_tvcmp(to->end, from->end) < 0 ) {
00542             to->end = from->end; /* use the latest time */
00543             from->end = ast_tv(0,0); /* we actively "steal" these values */
00544             to->duration = to->end.tv_sec - to->start.tv_sec;  /* don't forget to update the duration, billsec, when we set end */
00545             to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
00546          }
00547          /* else, nothing to do */
00548       } else {
00549          to->end = from->end;
00550          from->end = ast_tv(0,0); /* we actively "steal" these values */
00551          to->duration = to->end.tv_sec - to->start.tv_sec;
00552          to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
00553       }
00554    }
00555    if (to->disposition < from->disposition) {
00556       to->disposition = from->disposition;
00557       from->disposition = AST_CDR_NOANSWER;
00558    }
00559    if (ast_strlen_zero(to->lastapp) && !ast_strlen_zero(from->lastapp)) {
00560       ast_copy_string(to->lastapp, from->lastapp, sizeof(to->lastapp));
00561       from->lastapp[0] = 0; /* theft */
00562    }
00563    if (ast_strlen_zero(to->lastdata) && !ast_strlen_zero(from->lastdata)) {
00564       ast_copy_string(to->lastdata, from->lastdata, sizeof(to->lastdata));
00565       from->lastdata[0] = 0; /* theft */
00566    }
00567    if (ast_strlen_zero(to->dcontext) && !ast_strlen_zero(from->dcontext)) {
00568       ast_copy_string(to->dcontext, from->dcontext, sizeof(to->dcontext));
00569       from->dcontext[0] = 0; /* theft */
00570    }
00571    if (ast_strlen_zero(to->dstchannel) && !ast_strlen_zero(from->dstchannel)) {
00572       ast_copy_string(to->dstchannel, from->dstchannel, sizeof(to->dstchannel));
00573       from->dstchannel[0] = 0; /* theft */
00574    }
00575    if (ast_strlen_zero(to->channel) && !ast_strlen_zero(from->channel)) {
00576       ast_copy_string(to->channel, from->channel, sizeof(to->channel));
00577       from->channel[0] = 0; /* theft */
00578    }
00579    if (ast_strlen_zero(to->src) && !ast_strlen_zero(from->src)) {
00580       ast_copy_string(to->src, from->src, sizeof(to->src));
00581       from->src[0] = 0; /* theft */
00582    }
00583    if (ast_strlen_zero(to->dst) && !ast_strlen_zero(from->dst)) {
00584       ast_copy_string(to->dst, from->dst, sizeof(to->dst));
00585       from->dst[0] = 0; /* theft */
00586    }
00587    if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (!to->amaflags && from->amaflags)) {
00588       to->amaflags = from->amaflags;
00589       from->amaflags = 0; /* theft */
00590    }
00591    if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->accountcode) && !ast_strlen_zero(from->accountcode))) {
00592       ast_copy_string(to->accountcode, from->accountcode, sizeof(to->accountcode));
00593       from->accountcode[0] = 0; /* theft */
00594    }
00595    if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->userfield) && !ast_strlen_zero(from->userfield))) {
00596       ast_copy_string(to->userfield, from->userfield, sizeof(to->userfield));
00597       from->userfield[0] = 0; /* theft */
00598    }
00599    /* flags, varsead, ? */
00600    cdr_merge_vars(from, to);
00601 
00602    if (ast_test_flag(from, AST_CDR_FLAG_KEEP_VARS))
00603       ast_set_flag(to, AST_CDR_FLAG_KEEP_VARS);
00604    if (ast_test_flag(from, AST_CDR_FLAG_POSTED))
00605       ast_set_flag(to, AST_CDR_FLAG_POSTED);
00606    if (ast_test_flag(from, AST_CDR_FLAG_LOCKED))
00607       ast_set_flag(to, AST_CDR_FLAG_LOCKED);
00608    if (ast_test_flag(from, AST_CDR_FLAG_CHILD))
00609       ast_set_flag(to, AST_CDR_FLAG_CHILD);
00610    if (ast_test_flag(from, AST_CDR_FLAG_POST_DISABLED))
00611       ast_set_flag(to, AST_CDR_FLAG_POST_DISABLED);
00612 
00613    /* last, but not least, we need to merge any forked CDRs to the 'to' cdr */
00614    while (from->next) {
00615       /* just rip 'em off the 'from' and insert them on the 'to' */
00616       tcdr = from->next;
00617       from->next = tcdr->next;
00618       tcdr->next = NULL;
00619       /* tcdr is now ripped from the current list; */
00620       ast_cdr_append(to, tcdr);
00621    }
00622 }

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 929 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_NOANSWER, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, ast_flags::flags, ast_cdr::next, and ast_cdr::start.

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

00930 {
00931    struct ast_cdr *dup;
00932    struct ast_flags flags = { 0 };
00933 
00934    if (_flags)
00935       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
00936 
00937    for ( ; cdr ; cdr = cdr->next) {
00938       /* Detach if post is requested */
00939       if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00940          if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
00941             ast_cdr_end(cdr);
00942             if ((dup = ast_cdr_dup(cdr))) {
00943                ast_cdr_detach(dup);
00944             }
00945             ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
00946          }
00947 
00948          /* clear variables */
00949          if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
00950             ast_cdr_free_vars(cdr, 0);
00951          }
00952 
00953          /* Reset to initial state */
00954          ast_clear_flag(cdr, AST_FLAGS_ALL); 
00955          memset(&cdr->start, 0, sizeof(cdr->start));
00956          memset(&cdr->end, 0, sizeof(cdr->end));
00957          memset(&cdr->answer, 0, sizeof(cdr->answer));
00958          cdr->billsec = 0;
00959          cdr->duration = 0;
00960          ast_cdr_start(cdr);
00961          cdr->disposition = AST_CDR_NOANSWER;
00962       }
00963    }
00964 }

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

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

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

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

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

00822 {
00823    struct ast_cdr *cdr = chan->cdr;
00824 
00825    ast_string_field_set(chan, accountcode, account);
00826    for ( ; cdr ; cdr = cdr->next) {
00827       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00828          ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode));
00829       }
00830    }
00831    return 0;
00832 }

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

Definition at line 834 of file cdr.c.

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

Referenced by cdr_write(), and pbx_builtin_setamaflags().

00835 {
00836    struct ast_cdr *cdr;
00837    int newflag = ast_cdr_amaflags2int(flag);
00838    if (newflag) {
00839       for (cdr = chan->cdr; cdr; cdr = cdr->next)
00840          cdr->amaflags = newflag;
00841    }
00842 
00843    return 0;
00844 }

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

00708 {
00709 
00710    for (; cdr; cdr = cdr->next) {
00711       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00712          check_post(cdr);
00713          if (!app)
00714             app = "";
00715          ast_copy_string(cdr->lastapp, app, sizeof(cdr->lastapp));
00716          if (!data)
00717             data = "";
00718          ast_copy_string(cdr->lastdata, data, sizeof(cdr->lastdata));
00719       }
00720    }
00721 }

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

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

Referenced by ast_set_callerid().

00744 {
00745    for (; cdr; cdr = cdr->next) {
00746       if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00747          set_one_cid(cdr, c);
00748    }
00749    return 0;
00750 }

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

00699 {
00700    for (; cdr; cdr = cdr->next) {
00701       check_post(cdr);
00702       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00703          ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
00704    }
00705 }

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

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

00847 {
00848    struct ast_cdr *cdr = chan->cdr;
00849 
00850    for ( ; cdr ; cdr = cdr->next) {
00851       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 
00852          ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
00853    }
00854 
00855    return 0;
00856 }

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

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

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

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

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(), ast_pbx_outgoing_exten(), builtin_blindtransfer(), clear_caller(), and findmeexec().

00625 {
00626    char *chan; 
00627 
00628    for (; cdr; cdr = cdr->next) {
00629       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00630          chan = S_OR(cdr->channel, "<unknown>");
00631          check_post(cdr);
00632          check_start(cdr);
00633          cdr->start = ast_tvnow();
00634       }
00635    }
00636 }

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

01021 {
01022    struct ast_cdr_batch_item *oldbatchitems = NULL;
01023    pthread_attr_t attr;
01024    pthread_t batch_post_thread = AST_PTHREADT_NULL;
01025 
01026    /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
01027    if (!batch || !batch->head)
01028       return;
01029 
01030    /* move the old CDRs aside, and prepare a new CDR batch */
01031    ast_mutex_lock(&cdr_batch_lock);
01032    oldbatchitems = batch->head;
01033    reset_batch();
01034    ast_mutex_unlock(&cdr_batch_lock);
01035 
01036    /* if configured, spawn a new thread to post these CDRs,
01037       also try to save as much as possible if we are shutting down safely */
01038    if (batchscheduleronly || shutdown) {
01039       if (option_debug)
01040          ast_log(LOG_DEBUG, "CDR single-threaded batch processing begins now\n");
01041       do_batch_backend_process(oldbatchitems);
01042    } else {
01043       pthread_attr_init(&attr);
01044       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01045       if (ast_pthread_create_background(&batch_post_thread, &attr, do_batch_backend_process, oldbatchitems)) {
01046          ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
01047          do_batch_backend_process(oldbatchitems);
01048       } else {
01049          if (option_debug)
01050             ast_log(LOG_DEBUG, "CDR multi-threaded batch processing begins now\n");
01051       }
01052       pthread_attr_destroy(&attr);
01053    }
01054 }

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

References AST_CDR_FLAG_LOCKED, ast_check_hangup(), 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().

00873 {
00874    struct ast_cdr *cdr = c->cdr;
00875 
00876    for ( ; cdr ; cdr = cdr->next) {
00877       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00878          set_one_cid(cdr, c);
00879 
00880          /* Copy account code et-al */ 
00881          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00882          if (!ast_check_hangup(c)) {
00883             /* Destination information */ /* XXX privilege macro* ? */
00884             ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst));
00885             ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext));
00886          }
00887       }
00888    }
00889 
00890    return 0;
00891 }

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 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          localtime_r(&t, &tm);
00212          strftime(buf, bufsize, fmt, &tm);
00213       }
00214    }
00215 }

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

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

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

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

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

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

static void check_start ( struct ast_cdr cdr  )  [static]

print a warning if cdr already started

Definition at line 425 of file cdr.c.

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

Referenced by ast_cdr_start().

00426 {
00427    if (!cdr)
00428       return;
00429    if (!ast_tvzero(cdr->start))
00430       ast_log(LOG_NOTICE, "CDR on channel '%s' already started\n", S_OR(cdr->channel, "<unknown>"));
00431 }

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

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

01004 {
01005    struct ast_cdr_batch_item *processeditem;
01006    struct ast_cdr_batch_item *batchitem = data;
01007 
01008    /* Push each CDR into storage mechanism(s) and free all the memory */
01009    while (batchitem) {
01010       post_cdr(batchitem->cdr);
01011       ast_cdr_free(batchitem->cdr);
01012       processeditem = batchitem;
01013       batchitem = batchitem->next;
01014       free(processeditem);
01015    }
01016 
01017    return NULL;
01018 }

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

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

01135 {
01136    struct timespec timeout;
01137    int schedms;
01138    int numevents = 0;
01139 
01140    for(;;) {
01141       struct timeval now;
01142       schedms = ast_sched_wait(sched);
01143       /* this shouldn't happen, but provide a 1 second default just in case */
01144       if (schedms <= 0)
01145          schedms = 1000;
01146       now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
01147       timeout.tv_sec = now.tv_sec;
01148       timeout.tv_nsec = now.tv_usec * 1000;
01149       /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
01150       ast_mutex_lock(&cdr_pending_lock);
01151       ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
01152       numevents = ast_sched_runq(sched);
01153       ast_mutex_unlock(&cdr_pending_lock);
01154       if (option_debug > 1)
01155          ast_log(LOG_DEBUG, "Processed %d scheduled CDR batches from the run queue\n", numevents);
01156    }
01157 
01158    return NULL;
01159 }

static int do_reload ( void   )  [static]

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

01221 {
01222    struct ast_config *config;
01223    const char *enabled_value;
01224    const char *batched_value;
01225    const char *scheduleronly_value;
01226    const char *batchsafeshutdown_value;
01227    const char *size_value;
01228    const char *time_value;
01229    const char *end_before_h_value;
01230    int cfg_size;
01231    int cfg_time;
01232    int was_enabled;
01233    int was_batchmode;
01234    int res=0;
01235 
01236    ast_mutex_lock(&cdr_batch_lock);
01237 
01238    batchsize = BATCH_SIZE_DEFAULT;
01239    batchtime = BATCH_TIME_DEFAULT;
01240    batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
01241    batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
01242    was_enabled = enabled;
01243    was_batchmode = batchmode;
01244    enabled = 1;
01245    batchmode = 0;
01246 
01247    /* don't run the next scheduled CDR posting while reloading */
01248    if (cdr_sched > -1)
01249       ast_sched_del(sched, cdr_sched);
01250 
01251    if ((config = ast_config_load("cdr.conf"))) {
01252       if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
01253          enabled = ast_true(enabled_value);
01254       }
01255       if ((batched_value = ast_variable_retrieve(config, "general", "batch"))) {
01256          batchmode = ast_true(batched_value);
01257       }
01258       if ((scheduleronly_value = ast_variable_retrieve(config, "general", "scheduleronly"))) {
01259          batchscheduleronly = ast_true(scheduleronly_value);
01260       }
01261       if ((batchsafeshutdown_value = ast_variable_retrieve(config, "general", "safeshutdown"))) {
01262          batchsafeshutdown = ast_true(batchsafeshutdown_value);
01263       }
01264       if ((size_value = ast_variable_retrieve(config, "general", "size"))) {
01265          if (sscanf(size_value, "%d", &cfg_size) < 1)
01266             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", size_value);
01267          else if (size_value < 0)
01268             ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
01269          else
01270             batchsize = cfg_size;
01271       }
01272       if ((time_value = ast_variable_retrieve(config, "general", "time"))) {
01273          if (sscanf(time_value, "%d", &cfg_time) < 1)
01274             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", time_value);
01275          else if (time_value < 0)
01276             ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
01277          else
01278             batchtime = cfg_time;
01279       }
01280       if ((end_before_h_value = ast_variable_retrieve(config, "general", "endbeforehexten")))
01281          ast_set2_flag(&ast_options, ast_true(end_before_h_value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
01282    }
01283 
01284    if (enabled && !batchmode) {
01285       ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
01286    } else if (enabled && batchmode) {
01287       cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01288       ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
01289    } else {
01290       ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
01291    }
01292 
01293    /* if this reload enabled the CDR batch mode, create the background thread
01294       if it does not exist */
01295    if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
01296       ast_cond_init(&cdr_pending_cond, NULL);
01297       if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
01298          ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
01299          ast_sched_del(sched, cdr_sched);
01300       } else {
01301          ast_cli_register(&cli_submit);
01302          ast_register_atexit(ast_cdr_engine_term);
01303          res = 0;
01304       }
01305    /* if this reload disabled the CDR and/or batch mode and there is a background thread,
01306       kill it */
01307    } else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
01308       /* wake up the thread so it will exit */
01309       pthread_cancel(cdr_thread);
01310       pthread_kill(cdr_thread, SIGURG);
01311       pthread_join(cdr_thread, NULL);
01312       cdr_thread = AST_PTHREADT_NULL;
01313       ast_cond_destroy(&cdr_pending_cond);
01314       ast_cli_unregister(&cli_submit);
01315       ast_unregister_atexit(ast_cdr_engine_term);
01316       res = 0;
01317       /* if leaving batch mode, then post the CDRs in the batch,
01318          and don't reschedule, since we are stopping CDR logging */
01319       if (!batchmode && was_batchmode) {
01320          ast_cdr_engine_term();
01321       }
01322    } else {
01323       res = 0;
01324    }
01325 
01326    ast_mutex_unlock(&cdr_batch_lock);
01327    ast_config_destroy(config);
01328 
01329    return res;
01330 }

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

Definition at line 1161 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.

01162 {
01163    struct ast_cdr_beitem *beitem=NULL;
01164    int cnt=0;
01165    long nextbatchtime=0;
01166 
01167    if (argc > 2)
01168       return RESULT_SHOWUSAGE;
01169 
01170    ast_cli(fd, "CDR logging: %s\n", enabled ? "enabled" : "disabled");
01171    ast_cli(fd, "CDR mode: %s\n", batchmode ? "batch" : "simple");
01172    if (enabled) {
01173       if (batchmode) {
01174          if (batch)
01175             cnt = batch->size;
01176          if (cdr_sched > -1)
01177             nextbatchtime = ast_sched_when(sched, cdr_sched);
01178          ast_cli(fd, "CDR safe shut down: %s\n", batchsafeshutdown ? "enabled" : "disabled");
01179          ast_cli(fd, "CDR batch threading model: %s\n", batchscheduleronly ? "scheduler only" : "scheduler plus separate threads");
01180          ast_cli(fd, "CDR current batch size: %d record%s\n", cnt, (cnt != 1) ? "s" : "");
01181          ast_cli(fd, "CDR maximum batch size: %d record%s\n", batchsize, (batchsize != 1) ? "s" : "");
01182          ast_cli(fd, "CDR maximum batch time: %d second%s\n", batchtime, (batchtime != 1) ? "s" : "");
01183          ast_cli(fd, "CDR next scheduled batch processing time: %ld second%s\n", nextbatchtime, (nextbatchtime != 1) ? "s" : "");
01184       }
01185       AST_LIST_LOCK(&be_list);
01186       AST_LIST_TRAVERSE(&be_list, beitem, list) {
01187          ast_cli(fd, "CDR registered backend: %s\n", beitem->name);
01188       }
01189       AST_LIST_UNLOCK(&be_list);
01190    }
01191 
01192    return 0;
01193 }

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

Definition at line 1195 of file cdr.c.

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

01196 {
01197    if (argc > 2)
01198       return RESULT_SHOWUSAGE;
01199 
01200    submit_unscheduled_batch();
01201    ast_cli(fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
01202 
01203    return 0;
01204 }

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 992 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

00993 {
00994    /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
00995    if (!(batch = ast_malloc(sizeof(*batch))))
00996       return -1;
00997 
00998    reset_batch();
00999 
01000    return 0;
01001 }

static void post_cdr ( struct ast_cdr cdr  )  [static]

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

00907 {
00908    char *chan;
00909    struct ast_cdr_beitem *i;
00910 
00911    for ( ; cdr ; cdr = cdr->next) {
00912       chan = S_OR(cdr->channel, "<unknown>");
00913       check_post(cdr);
00914       if (ast_tvzero(cdr->end))
00915          ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan);
00916       if (ast_tvzero(cdr->start))
00917          ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
00918       ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
00919       if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
00920          continue;
00921       AST_LIST_LOCK(&be_list);
00922       AST_LIST_TRAVERSE(&be_list, i, list) {
00923          i->be(cdr);
00924       }
00925       AST_LIST_UNLOCK(&be_list);
00926    }
00927 }

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

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

00985 {
00986    batch->size = 0;
00987    batch->head = NULL;
00988    batch->tail = NULL;
00989 }

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

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

00725 {
00726    /* Grab source from ANI or normal Caller*ID */
00727    const char *num = S_OR(c->cid.cid_ani, c->cid.cid_num);
00728    if (!cdr)
00729       return;
00730    if (!ast_strlen_zero(c->cid.cid_name)) {
00731       if (!ast_strlen_zero(num)) /* both name and number */
00732          snprintf(cdr->clid, sizeof(cdr->clid), "\"%s\" <%s>", c->cid.cid_name, num);
00733       else           /* only name */
00734          ast_copy_string(cdr->clid, c->cid.cid_name, sizeof(cdr->clid));
00735    } else if (!ast_strlen_zero(num)) { /* only number */
00736       ast_copy_string(cdr->clid, num, sizeof(cdr->clid));
00737    } else {          /* nothing known */
00738       cdr->clid[0] = '\0';
00739    }
00740    ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src));
00741 
00742 }

static int submit_scheduled_batch ( void *  data  )  [static]

Definition at line 1056 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

01057 {
01058    ast_cdr_submit_batch(0);
01059    /* manually reschedule from this point in time */
01060    cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01061    /* returning zero so the scheduler does not automatically reschedule */
01062    return 0;
01063 }

static void submit_unscheduled_batch ( void   )  [static]

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

01066 {
01067    /* this is okay since we are not being called from within the scheduler */
01068    if (cdr_sched > -1)
01069       ast_sched_del(sched, cdr_sched);
01070    /* schedule the submission to occur ASAP (1 ms) */
01071    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
01072    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
01073    ast_mutex_lock(&cdr_pending_lock);
01074    ast_cond_signal(&cdr_pending_cond);
01075    ast_mutex_unlock(&cdr_pending_lock);
01076 }


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

Referenced by ast_cdr_engine_init(), and dnsmgr_init().

struct ast_cli_entry cli_submit [static]

Definition at line 1206 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(), destroy_peer(), 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(), 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 Mon May 14 04:45:08 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1