Tue Nov 4 13:20:27 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"

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
#define NOAPPLICATION_DEFAULT   1

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)
int check_cdr_enabled ()
 Return TRUE if CDR subsystem is enabled.
static void check_post (struct ast_cdr *cdr)
 print a warning if cdr already posted
static void * do_batch_backend_process (void *data)
static void * do_cdr (void *data)
static int do_reload (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 int noapplication
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().

#define NOAPPLICATION_DEFAULT   1

Definition at line 90 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(), 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 978 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().

00979 {
00980    if (!strcasecmp(flag, "default"))
00981       return 0;
00982    if (!strcasecmp(flag, "omit"))
00983       return AST_CDR_OMIT;
00984    if (!strcasecmp(flag, "billing"))
00985       return AST_CDR_BILLING;
00986    if (!strcasecmp(flag, "documentation"))
00987       return AST_CDR_DOCUMENTATION;
00988    return -1;
00989 }

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

00701 {
00702 
00703    for (; cdr; cdr = cdr->next) {
00704       check_post(cdr);
00705       if (cdr->disposition < AST_CDR_ANSWERED)
00706          cdr->disposition = AST_CDR_ANSWERED;
00707       if (ast_tvzero(cdr->answer))
00708          cdr->answer = ast_tvnow();
00709    }
00710 }

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

Definition at line 1058 of file cdr.c.

References ast_cdr::next.

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

01059 {
01060    struct ast_cdr *ret;
01061 
01062    if (cdr) {
01063       ret = cdr;
01064 
01065       while (cdr->next)
01066          cdr = cdr->next;
01067       cdr->next = newcdr;
01068    } else {
01069       ret = newcdr;
01070    }
01071 
01072    return ret;
01073 }

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

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

00945 {
00946    struct ast_cdr *cdr = chan->cdr;
00947 
00948    for ( ; cdr ; cdr = cdr->next) {
00949       int len = strlen(cdr->userfield);
00950 
00951       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00952          ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
00953    }
00954 
00955    return 0;
00956 }

void ast_cdr_busy ( struct ast_cdr cdr  ) 

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

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

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

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

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

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

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

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_async_goto(), ast_bridge_call(), and ast_cdr_merge().

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

00874 {
00875    switch (disposition) {
00876    case AST_CDR_NULL:
00877       return "NO ANSWER"; /* by default, for backward compatibility */
00878    case AST_CDR_NOANSWER:
00879       return "NO ANSWER";
00880    case AST_CDR_FAILED:
00881       return "FAILED";     
00882    case AST_CDR_BUSY:
00883       return "BUSY";    
00884    case AST_CDR_ANSWERED:
00885       return "ANSWERED";
00886    }
00887    return "UNKNOWN";
00888 }

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

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

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

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

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 858 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_fork(), ast_cdr_reset(), ast_feature_request_and_dial(), ast_hangup(), ast_pbx_outgoing_cdr_failed(), clear_caller(), and findmeexec().

00859 {
00860    for ( ; cdr ; cdr = cdr->next) {
00861       check_post(cdr);
00862       if (ast_tvzero(cdr->end))
00863          cdr->end = ast_tvnow();
00864       if (ast_tvzero(cdr->start)) {
00865          ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
00866          cdr->disposition = AST_CDR_FAILED;
00867       } else
00868          cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
00869       cdr->billsec = ast_tvzero(cdr->answer) ? 0 : cdr->end.tv_sec - cdr->answer.tv_sec;
00870    }
00871 }

int ast_cdr_engine_init ( void   ) 

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

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

01437 {
01438    int res;
01439 
01440    sched = sched_context_create();
01441    if (!sched) {
01442       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
01443       return -1;
01444    }
01445 
01446    ast_cli_register(&cli_status);
01447 
01448    res = do_reload();
01449    if (res) {
01450       ast_mutex_lock(&cdr_batch_lock);
01451       res = init_batch();
01452       ast_mutex_unlock(&cdr_batch_lock);
01453    }
01454 
01455    return res;
01456 }

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1465 of file cdr.c.

References do_reload().

01466 {
01467    return do_reload();
01468 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1460 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01461 {
01462    ast_cdr_submit_batch(batchsafeshutdown);
01463 }

void ast_cdr_failed ( struct ast_cdr cdr  ) 

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

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

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

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

00892 {
00893    switch(flag) {
00894    case AST_CDR_OMIT:
00895       return "OMIT";
00896    case AST_CDR_BILLING:
00897       return "BILLING";
00898    case AST_CDR_DOCUMENTATION:
00899       return "DOCUMENTATION";
00900    }
00901    return "Unknown";
00902 }

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

00413 {
00414 
00415    /* clear variables */
00416    for (; cdr; cdr = recur ? cdr->next : NULL) {
00417       struct ast_var_t *vardata;
00418       struct varshead *headp = &cdr->varshead;
00419       while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
00420          ast_var_delete(vardata);
00421    }
00422 }

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

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

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

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

00194 {
00195    if (ast_strlen_zero(name))
00196       return NULL;
00197 
00198    for (; cdr; cdr = recur ? cdr->next : NULL) {
00199       struct ast_var_t *variables;
00200       struct varshead *headp = &cdr->varshead;
00201       AST_LIST_TRAVERSE(headp, variables, entries) {
00202          if (!strcasecmp(name, ast_var_name(variables)))
00203             return ast_var_value(variables);
00204       }
00205    }
00206 
00207    return NULL;
00208 }

int ast_cdr_init ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

Parameters:
cdr Call Detail Record to use for channel
chan Channel to bind CDR with Initializes a CDR and associates it with a particular channel Return is negligible. (returns 0 by default)

Definition at line 823 of file cdr.c.

References ast_channel::_state, ast_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().

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

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

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

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

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

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 115 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(), odbc_load_module(), process_my_load_module(), and tds_load_module().

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

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

01022 {
01023    struct ast_cdr *dup;
01024    struct ast_flags flags = { 0 };
01025 
01026    if (_flags)
01027       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
01028 
01029    for ( ; cdr ; cdr = cdr->next) {
01030       /* Detach if post is requested */
01031       if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01032          if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
01033             ast_cdr_end(cdr);
01034             if ((dup = ast_cdr_dup(cdr))) {
01035                ast_cdr_detach(dup);
01036             }
01037             ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
01038          }
01039 
01040          /* clear variables */
01041          if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
01042             ast_cdr_free_vars(cdr, 0);
01043          }
01044 
01045          /* Reset to initial state */
01046          ast_clear_flag(cdr, AST_FLAGS_ALL); 
01047          memset(&cdr->start, 0, sizeof(cdr->start));
01048          memset(&cdr->end, 0, sizeof(cdr->end));
01049          memset(&cdr->answer, 0, sizeof(cdr->answer));
01050          cdr->billsec = 0;
01051          cdr->duration = 0;
01052          ast_cdr_start(cdr);
01053          cdr->disposition = AST_CDR_NULL;
01054       }
01055    }
01056 }

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

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

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

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

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

00905 {
00906    struct ast_cdr *cdr = chan->cdr;
00907 
00908    ast_string_field_set(chan, accountcode, account);
00909    for ( ; cdr ; cdr = cdr->next) {
00910       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00911          ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode));
00912       }
00913    }
00914    return 0;
00915 }

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

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

00918 {
00919    struct ast_cdr *cdr;
00920    int newflag = ast_cdr_amaflags2int(flag);
00921    if (newflag) {
00922       for (cdr = chan->cdr; cdr; cdr = cdr->next) {
00923          if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00924             cdr->amaflags = newflag;
00925          }
00926       }
00927    }
00928 
00929    return 0;
00930 }

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

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

int ast_cdr_setcid ( struct ast_cdr cdr,
struct ast_channel chan 
)

Parameters:
cdr Call Detail Record to use for channel
chan Channel to bind CDR with Initializes a CDR and associates it with a particular channel Return is negligible. (returns 0 by default)

Definition at line 814 of file cdr.c.

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

Referenced by ast_set_callerid().

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

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

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

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

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

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

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

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

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 299 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 ast_cdr_fork(), and cdr_write().

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

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

00688 {
00689    char *chan; 
00690 
00691    for (; cdr; cdr = cdr->next) {
00692       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00693          chan = S_OR(cdr->channel, "<unknown>");
00694          check_post(cdr);
00695          cdr->start = ast_tvnow();
00696       }
00697    }
00698 }

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

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

void ast_cdr_unregister ( const char *  name  ) 

unregister a CDR driver

Definition at line 153 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(), reload(), tds_unload_module(), and unload_module().

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

int ast_cdr_update ( struct ast_channel c  ) 

Definition at line 958 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(), findmeexec(), and local_call().

00959 {
00960    struct ast_cdr *cdr = c->cdr;
00961 
00962    for ( ; cdr ; cdr = cdr->next) {
00963       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00964          set_one_cid(cdr, c);
00965 
00966          /* Copy account code et-al */ 
00967          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00968          
00969          /* Destination information */ /* XXX privilege macro* ? */
00970          ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst));
00971          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext));
00972       }
00973    }
00974 
00975    return 0;
00976 }

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

References ast_localtime(), and t.

Referenced by ast_cdr_getvar().

00211 {
00212    if (fmt == NULL) {   /* raw mode */
00213       snprintf(buf, bufsize, "%ld.%06ld", (long)tv.tv_sec, (long)tv.tv_usec);
00214    } else {  
00215       time_t t = tv.tv_sec;
00216       if (t) {
00217          struct tm tm;
00218 
00219          ast_localtime(&t, &tm, NULL);
00220          strftime(buf, bufsize, fmt, &tm);
00221       }
00222    }
00223 }

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 = NULL, *fromvarval = NULL;
00480       const char *tovarname = NULL, *tovarval = NULL;
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 }

int check_cdr_enabled ( void   ) 

Return TRUE if CDR subsystem is enabled.

Definition at line 107 of file cdr.c.

References enabled.

Referenced by action_coresettings(), and handle_show_settings().

00108 {
00109    return enabled;
00110 }

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

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

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

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

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

01096 {
01097    struct ast_cdr_batch_item *processeditem;
01098    struct ast_cdr_batch_item *batchitem = data;
01099 
01100    /* Push each CDR into storage mechanism(s) and free all the memory */
01101    while (batchitem) {
01102       post_cdr(batchitem->cdr);
01103       ast_cdr_free(batchitem->cdr);
01104       processeditem = batchitem;
01105       batchitem = batchitem->next;
01106       free(processeditem);
01107    }
01108 
01109    return NULL;
01110 }

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

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

01226 {
01227    struct timespec timeout;
01228    int schedms;
01229    int numevents = 0;
01230 
01231    for(;;) {
01232       struct timeval now;
01233       schedms = ast_sched_wait(sched);
01234       /* this shouldn't happen, but provide a 1 second default just in case */
01235       if (schedms <= 0)
01236          schedms = 1000;
01237       now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
01238       timeout.tv_sec = now.tv_sec;
01239       timeout.tv_nsec = now.tv_usec * 1000;
01240       /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
01241       ast_mutex_lock(&cdr_pending_lock);
01242       ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
01243       numevents = ast_sched_runq(sched);
01244       ast_mutex_unlock(&cdr_pending_lock);
01245       if (option_debug > 1)
01246          ast_log(LOG_DEBUG, "Processed %d scheduled CDR batches from the run queue\n", numevents);
01247    }
01248 
01249    return NULL;
01250 }

static int do_reload ( void   )  [static]

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

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

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

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

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

01253 {
01254    struct ast_cdr_beitem *beitem=NULL;
01255    int cnt=0;
01256    long nextbatchtime=0;
01257 
01258    if (argc > 2)
01259       return RESULT_SHOWUSAGE;
01260 
01261    ast_cli(fd, "CDR logging: %s\n", enabled ? "enabled" : "disabled");
01262    ast_cli(fd, "CDR mode: %s\n", batchmode ? "batch" : "simple");
01263    if (enabled) {
01264       ast_cli(fd, "CDR output unanswered calls: %s\n", unanswered ? "yes" : "no");
01265       if (unanswered) {
01266          ast_cli(fd, "CDR output no application calls: %s\n", noapplication ? "yes" : "no");
01267       }
01268       if (batchmode) {
01269          if (batch)
01270             cnt = batch->size;
01271          if (cdr_sched > -1)
01272             nextbatchtime = ast_sched_when(sched, cdr_sched);
01273          ast_cli(fd, "CDR safe shut down: %s\n", batchsafeshutdown ? "enabled" : "disabled");
01274          ast_cli(fd, "CDR batch threading model: %s\n", batchscheduleronly ? "scheduler only" : "scheduler plus separate threads");
01275          ast_cli(fd, "CDR current batch size: %d record%s\n", cnt, (cnt != 1) ? "s" : "");
01276          ast_cli(fd, "CDR maximum batch size: %d record%s\n", batchsize, (batchsize != 1) ? "s" : "");
01277          ast_cli(fd, "CDR maximum batch time: %d second%s\n", batchtime, (batchtime != 1) ? "s" : "");
01278          ast_cli(fd, "CDR next scheduled batch processing time: %ld second%s\n", nextbatchtime, (nextbatchtime != 1) ? "s" : "");
01279       }
01280       AST_LIST_LOCK(&be_list);
01281       AST_LIST_TRAVERSE(&be_list, beitem, list) {
01282          ast_cli(fd, "CDR registered backend: %s\n", beitem->name);
01283       }
01284       AST_LIST_UNLOCK(&be_list);
01285    }
01286 
01287    return 0;
01288 }

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

Definition at line 1290 of file cdr.c.

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

01291 {
01292    if (argc > 2)
01293       return RESULT_SHOWUSAGE;
01294 
01295    submit_unscheduled_batch();
01296    ast_cli(fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
01297 
01298    return 0;
01299 }

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1084 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

01085 {
01086    /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
01087    if (!(batch = ast_malloc(sizeof(*batch))))
01088       return -1;
01089 
01090    reset_batch();
01091 
01092    return 0;
01093 }

static void post_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 991 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, ast_cdr::lastapp, LOG_WARNING, ast_cdr::next, noapplication, S_OR, ast_cdr::start, and unanswered.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

00992 {
00993    char *chan;
00994    struct ast_cdr_beitem *i;
00995 
00996    for ( ; cdr ; cdr = cdr->next) {
00997       if ( (!unanswered && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) ||
00998              (unanswered && !noapplication && ast_strlen_zero(cdr->lastapp)) ) {
00999          /* For people, who don't want to see unanswered single-channel events */
01000          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01001          continue;
01002       }
01003 
01004       chan = S_OR(cdr->channel, "<unknown>");
01005       check_post(cdr);
01006       if (ast_tvzero(cdr->end))
01007          ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan);
01008       if (ast_tvzero(cdr->start))
01009          ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
01010       ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
01011       if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
01012          continue;
01013       AST_LIST_LOCK(&be_list);
01014       AST_LIST_TRAVERSE(&be_list, i, list) {
01015          i->be(cdr);
01016       }
01017       AST_LIST_UNLOCK(&be_list);
01018    }
01019 }

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

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

01077 {
01078    batch->size = 0;
01079    batch->head = NULL;
01080    batch->tail = NULL;
01081 }

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

Definition at line 795 of file cdr.c.

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

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

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

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

Definition at line 1148 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

01149 {
01150    ast_cdr_submit_batch(0);
01151    /* manually reschedule from this point in time */
01152    cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01153    /* returning zero so the scheduler does not automatically reschedule */
01154    return 0;
01155 }

static void submit_unscheduled_batch ( void   )  [static]

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

01158 {
01159    /* this is okay since we are not being called from within the scheduler */
01160    AST_SCHED_DEL(sched, cdr_sched);
01161    /* schedule the submission to occur ASAP (1 ms) */
01162    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
01163    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
01164    ast_mutex_lock(&cdr_pending_lock);
01165    ast_cond_signal(&cdr_pending_cond);
01166    ast_mutex_unlock(&cdr_pending_lock);
01167 }


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

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

int batchsafeshutdown [static]

Definition at line 99 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 98 of file cdr.c.

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

int batchsize [static]

Definition at line 96 of file cdr.c.

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

int batchtime [static]

Definition at line 97 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 105 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 292 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 1308 of file cdr.c.

Referenced by ast_cdr_engine_init(), and dnsmgr_init().

struct ast_cli_entry cli_submit [static]

Definition at line 1301 of file cdr.c.

Referenced by do_reload().

int enabled [static]

Definition at line 92 of file cdr.c.

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

int noapplication [static]

Definition at line 94 of file cdr.c.

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

struct sched_context* sched [static]

Definition at line 82 of file cdr.c.

Referenced by __attempt_transmit(), __find_callno(), __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(), 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_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 93 of file cdr.c.

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


Generated on Tue Nov 4 13:20:27 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7