Fri Sep 25 19:28:22 2009

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

struct 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)
struct 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)
 the same as a cdr_free call, only with no checks; just get rid of it
char * ast_cdr_disp2str (int disposition)
int ast_cdr_disposition (struct ast_cdr *cdr, int cause)
struct 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.
int ast_cdr_log_unanswered (void)
void ast_cdr_merge (struct ast_cdr *to, struct ast_cdr *from)
void ast_cdr_noanswer (struct ast_cdr *cdr)
int ast_cdr_register (const char *name, const char *desc, ast_cdrbe be)
void ast_cdr_reset (struct ast_cdr *cdr, struct ast_flags *_flags)
int ast_cdr_serialize_variables (struct ast_cdr *cdr, char *buf, size_t size, char delim, char sep, int recur)
int ast_cdr_setaccount (struct ast_channel *chan, const char *account)
int ast_cdr_setamaflags (struct ast_channel *chan, const char *flag)
void ast_cdr_setapp (struct ast_cdr *cdr, char *app, char *data)
int ast_cdr_setcid (struct ast_cdr *cdr, struct ast_channel *c)
void ast_cdr_setdestchan (struct ast_cdr *cdr, const char *chann)
int ast_cdr_setuserfield (struct ast_channel *chan, const char *userfield)
int ast_cdr_setvar (struct ast_cdr *cdr, const char *name, const char *value, int recur)
void ast_cdr_start (struct ast_cdr *cdr)
void ast_cdr_submit_batch (int shutdown)
void ast_cdr_unregister (const char *name)
int ast_cdr_update (struct ast_channel *c)
static AST_LIST_HEAD_STATIC (be_list, ast_cdr_beitem)
 AST_MUTEX_DEFINE_STATIC (cdr_pending_lock)
 AST_MUTEX_DEFINE_STATIC (cdr_batch_lock)
static void cdr_get_tv (struct timeval tv, const char *fmt, char *buf, int bufsize)
static void cdr_merge_vars (struct ast_cdr *to, struct ast_cdr *from)
static void check_post (struct ast_cdr *cdr)
 print a warning if cdr already posted
static void * do_batch_backend_process (void *data)
static void * do_cdr (void *data)
static int do_reload (void)
static int handle_cli_status (int fd, int argc, char *argv[])
static int handle_cli_submit (int fd, int argc, char *argv[])
static int init_batch (void)
static void post_cdr (struct ast_cdr *cdr)
static void reset_batch (void)
static void set_one_cid (struct ast_cdr *cdr, struct ast_channel *c)
static int submit_scheduled_batch (const void *data)
static void submit_unscheduled_batch (void)

Variables

char ast_default_accountcode [AST_MAX_ACCOUNT_CODE]
int ast_default_amaflags = AST_CDR_DOCUMENTATION
static struct ast_cdr_batchbatch
static int batchmode
static int batchsafeshutdown
static int batchscheduleronly
static int batchsize
static int batchtime
static ast_cond_t cdr_pending_cond
static const char * cdr_readonly_vars []
static int cdr_sched = -1
static pthread_t cdr_thread = AST_PTHREADT_NULL
static struct ast_cli_entry cli_status
static struct ast_cli_entry cli_submit
static int enabled
static struct sched_contextsched
static int unanswered


Detailed Description

Call Detail Record API.

Author:
Mark Spencer <markster@digium.com>
Note:
Includes code and algorithms from the Zapata library.

We do a lot of checking here in the CDR code to try to be sure we don't ever let a CDR slip through our fingers somehow. If someone allocates a CDR, it must be completely handled normally or a WARNING shall be logged, so that we can best keep track of any escape condition where the CDR isn't properly generated and posted.

Definition in file cdr.c.


Define Documentation

#define BATCH_SAFE_SHUTDOWN_DEFAULT   1

Definition at line 89 of file cdr.c.

Referenced by do_reload().

#define BATCH_SCHEDULER_ONLY_DEFAULT   0

Definition at line 88 of file cdr.c.

Referenced by do_reload().

#define BATCH_SIZE_DEFAULT   100

Definition at line 86 of file cdr.c.

Referenced by do_reload().

#define BATCH_TIME_DEFAULT   300

Definition at line 87 of file cdr.c.

Referenced by do_reload().


Function Documentation

struct ast_cdr* ast_cdr_alloc ( void   )  [read]

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_channel_alloc(), ast_feature_request_and_dial(), ast_pbx_outgoing_app2(), 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  ) 

Convert a string to a detail record AMA flag

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

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

00975 {
00976    if (!strcasecmp(flag, "default"))
00977       return 0;
00978    if (!strcasecmp(flag, "omit"))
00979       return AST_CDR_OMIT;
00980    if (!strcasecmp(flag, "billing"))
00981       return AST_CDR_BILLING;
00982    if (!strcasecmp(flag, "documentation"))
00983       return AST_CDR_DOCUMENTATION;
00984    return -1;
00985 }

void ast_cdr_answer ( struct ast_cdr cdr  ) 

Answer a call

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

Definition at line 700 of file cdr.c.

References ast_cdr::answer, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, ast_test_flag, 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       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00705          check_post(cdr);
00706          if (cdr->disposition < AST_CDR_ANSWERED)
00707             cdr->disposition = AST_CDR_ANSWERED;
00708          if (ast_tvzero(cdr->answer))
00709             cdr->answer = ast_tvnow();
00710       }
00711    }
00712 }

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

Definition at line 1047 of file cdr.c.

References ast_cdr::next.

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

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

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

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

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

void ast_cdr_busy ( struct ast_cdr cdr  ) 

Busy a call

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

Definition at line 714 of file cdr.c.

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

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

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

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

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

void ast_cdr_detach ( struct ast_cdr cdr  ) 

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

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

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

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

void ast_cdr_discard ( struct ast_cdr cdr  ) 

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

Discard and free a CDR record.

Definition at line 453 of file cdr.c.

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

Referenced by 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  ) 

Disposition to a string

Parameters:
disposition input binary form Converts the binary form of a disposition to string form. Returns a pointer to the string form

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

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

int ast_cdr_disposition ( struct ast_cdr cdr,
int  cause 
)

Save the result of the call based on the AST_CAUSE_*

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

Definition at line 756 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_app2(), ast_pbx_outgoing_exten2(), clear_caller(), and findmeexec().

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

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

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

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

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

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

void ast_cdr_end ( struct ast_cdr cdr  ) 

End a call

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

Definition at line 852 of file cdr.c.

References ast_cdr::answer, AST_CDR_FAILED, AST_CDR_FLAG_LOCKED, ast_log(), ast_test_flag, ast_cdr::billsec, ast_cdr::channel, check_post(), ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, LOG_WARNING, ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by __ast_pbx_run(), __ast_read(), __ast_request_and_dial(), ast_cdr_reset(), ast_feature_request_and_dial(), ast_hangup(), ast_pbx_outgoing_cdr_failed(), clear_caller(), and findmeexec().

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

int ast_cdr_engine_init ( void   ) 

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

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

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

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1447 of file cdr.c.

References do_reload().

01448 {
01449    return do_reload();
01450 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1442 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01443 {
01444    ast_cdr_submit_batch(batchsafeshutdown);
01445 }

void ast_cdr_failed ( struct ast_cdr cdr  ) 

Fail a call

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

Definition at line 726 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_app2(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten2(), clear_caller(), and findmeexec().

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

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

00888 {
00889    switch(flag) {
00890    case AST_CDR_OMIT:
00891       return "OMIT";
00892    case AST_CDR_BILLING:
00893       return "BILLING";
00894    case AST_CDR_DOCUMENTATION:
00895       return "DOCUMENTATION";
00896    }
00897    return "Unknown";
00898 }

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

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

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

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

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

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

References ast_channel::_state, ast_cdr::accountcode, ast_channel::amaflags, ast_cdr::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NULL, AST_STATE_UP, ast_test_flag, ast_cdr::channel, ast_channel::context, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_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_channel_alloc(), ast_feature_request_and_dial(), ast_pbx_outgoing_app2(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

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

int ast_cdr_log_unanswered ( void   ) 

Definition at line 106 of file cdr.c.

References unanswered.

Referenced by wait_for_answer().

00107 {
00108    return unanswered;
00109 }

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  ) 

A call wasn't answered

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

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

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

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

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_cdr_beitem::be, ast_cdr_beitem::desc, LOG_WARNING, and ast_cdr_beitem::name.

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

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

void ast_cdr_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

Reset the detail record, optionally posting it first

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

Definition at line 1010 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_cdr::next, and ast_cdr::start.

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

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

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

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

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

References ast_cdr::accountcode, 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_app2(), ast_pbx_outgoing_exten2(), auth_exec(), cdr_write(), and rpt_call().

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

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

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

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

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

Set the last executed application

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

Definition at line 784 of file cdr.c.

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

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

00785 {
00786 
00787    for (; cdr; cdr = cdr->next) {
00788       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00789          check_post(cdr);
00790          if (!app)
00791             app = "";
00792          ast_copy_string(cdr->lastapp, app, sizeof(cdr->lastapp));
00793          if (!data)
00794             data = "";
00795          ast_copy_string(cdr->lastdata, data, sizeof(cdr->lastdata));
00796       }
00797    }
00798 }

int ast_cdr_setcid ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel

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

Definition at line 820 of file cdr.c.

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

Referenced by ast_set_callerid().

00821 {
00822    for (; cdr; cdr = cdr->next) {
00823       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00824          set_one_cid(cdr, c);
00825    }
00826    return 0;
00827 }

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

Set the destination channel, if there was one

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

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

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

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

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

00929 {
00930    struct ast_cdr *cdr = chan->cdr;
00931 
00932    for ( ; cdr ; cdr = cdr->next) {
00933       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 
00934          ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
00935    }
00936 
00937    return 0;
00938 }

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

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

Referenced by cdr_write().

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

void ast_cdr_start ( struct ast_cdr cdr  ) 

Start a call

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

Definition at line 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_channel_alloc(), ast_feature_request_and_dial(), ast_pbx_outgoing_app2(), 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  ) 

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

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

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

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

void ast_cdr_unregister ( const char *  name  ) 

unregister a CDR driver

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

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

int ast_cdr_update ( struct ast_channel c  ) 

Definition at line 954 of file cdr.c.

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

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

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

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

References ast_localtime(), and t.

Referenced by ast_cdr_getvar().

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

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 }

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

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

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

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

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

static int do_reload ( void   )  [static]

Definition at line 1302 of file cdr.c.

References ast_cdr_engine_term(), ast_cli_register(), ast_cli_unregister(), ast_cond_destroy(), ast_cond_init(), ast_config_destroy(), ast_config_load(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN, ast_options, ast_pthread_create_background, AST_PTHREADT_NULL, ast_register_atexit(), ast_sched_add(), ast_sched_del(), ast_set2_flag, ast_true(), ast_unregister_atexit(), ast_variable_retrieve(), BATCH_SAFE_SHUTDOWN_DEFAULT, BATCH_SCHEDULER_ONLY_DEFAULT, BATCH_SIZE_DEFAULT, BATCH_TIME_DEFAULT, batchmode, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_pending_cond, cdr_sched, cdr_thread, cli_submit, config, do_cdr(), enabled, LOG_ERROR, LOG_NOTICE, LOG_WARNING, submit_scheduled_batch(), and unanswered.

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

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

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

Definition at line 1242 of file cdr.c.

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

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

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

Definition at line 1277 of file cdr.c.

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

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

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1073 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

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

static void post_cdr ( struct ast_cdr cdr  )  [static]

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

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

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

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

01066 {
01067    batch->size = 0;
01068    batch->head = NULL;
01069    batch->tail = NULL;
01070 }

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

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

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

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

Definition at line 1137 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

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

static void submit_unscheduled_batch ( void   )  [static]

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

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


Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]

Definition at line 60 of file cdr.c.

Referenced by ast_channel_alloc().

int ast_default_amaflags = AST_CDR_DOCUMENTATION

Default AMA flag for billing records (CDR's)

Definition at line 59 of file cdr.c.

Referenced by ast_channel_alloc().

struct ast_cdr_batch * batch [static]

int batchmode [static]

Definition at line 93 of file cdr.c.

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

int batchsafeshutdown [static]

Definition at line 97 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 96 of file cdr.c.

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

int batchsize [static]

Definition at line 94 of file cdr.c.

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

int batchtime [static]

Definition at line 95 of file cdr.c.

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

Definition at line 103 of file cdr.c.

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

const char* cdr_readonly_vars[] [static]

Initial value:

 { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
                "lastapp", "lastdata", "start", "answer", "end", "duration",
                "billsec", "disposition", "amaflags", "accountcode", "uniqueid",
                "userfield", NULL }

Definition at line 291 of file cdr.c.

Referenced by ast_cdr_serialize_variables(), and ast_cdr_setvar().

int cdr_sched = -1 [static]

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 84 of file cdr.c.

Referenced by do_reload().

struct ast_cli_entry cli_status [static]

Definition at line 1295 of file cdr.c.

Referenced by ast_cdr_engine_init(), and dnsmgr_init().

struct ast_cli_entry cli_submit [static]

Definition at line 1288 of file cdr.c.

Referenced by do_reload().

int enabled [static]

struct sched_context* sched [static]

Definition at line 82 of file cdr.c.

int unanswered [static]

Is the CDR subsystem enabled ?

Definition at line 92 of file cdr.c.

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


Generated on Fri Sep 25 19:28:22 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.5