Thu Oct 8 21:56:12 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.
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 458 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_uniqueid(), ast_bridge_call(), ast_cdr_dup(), ast_channel_alloc(), ast_feature_request_and_dial(), ast_pbx_outgoing_app_uniqueid(), builtin_blindtransfer(), clear_caller(), findmeexec(), and start_monitor_exec().

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

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

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

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

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

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

Definition at line 1051 of file cdr.c.

References ast_cdr::next.

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

01052 {
01053    struct ast_cdr *ret;
01054 
01055    if (cdr) {
01056       ret = cdr;
01057 
01058       while (cdr->next)
01059          cdr = cdr->next;
01060       cdr->next = newcdr;
01061    } else {
01062       ret = newcdr;
01063    }
01064 
01065    return ret;
01066 }

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

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

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

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

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

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

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

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

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

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

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

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

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

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

References AST_CAUSE_BUSY, AST_CAUSE_NORMAL, ast_cdr_busy(), and ast_cdr::next.

Referenced by __ast_request_and_dial_uniqueid(), ast_feature_request_and_dial(), ast_pbx_outgoing_app_uniqueid(), ast_pbx_outgoing_exten_uniqueid(), clear_caller(), and findmeexec().

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

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

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

void ast_cdr_end ( struct ast_cdr cdr  ) 

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_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_pbx_run(), __ast_read(), __ast_request_and_dial_uniqueid(), ast_cdr_fork(), 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       check_post(cdr);
00856       if (ast_tvzero(cdr->end))
00857          cdr->end = ast_tvnow();
00858       if (ast_tvzero(cdr->start)) {
00859          ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
00860          cdr->disposition = AST_CDR_FAILED;
00861       } else
00862          cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
00863       cdr->billsec = ast_tvzero(cdr->answer) ? 0 : cdr->end.tv_sec - cdr->answer.tv_sec;
00864    }
00865 }

int ast_cdr_engine_init ( void   ) 

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

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

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

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1449 of file cdr.c.

References do_reload().

01450 {
01451    return do_reload();
01452 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1444 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01445 {
01446    ast_cdr_submit_batch(batchsafeshutdown);
01447 }

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 718 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_uniqueid(), ast_feature_request_and_dial(), ast_pbx_outgoing_app_uniqueid(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten_uniqueid(), clear_caller(), and findmeexec().

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

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

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

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

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

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

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

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

void ast_cdr_getvar ( struct ast_cdr cdr,
const char *  name,
char **  ret,
char *  workspace,
int  workspacelen,
int  recur,
int  raw 
)

CDR channel variable retrieval

Definition at line 220 of file cdr.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_disp2str(), ast_cdr_flags2str(), ast_cdr_getvar_internal(), ast_strlen_zero(), ast_cdr::billsec, cdr_get_tv(), ast_cdr::channel, ast_cdr::clid, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, fmt, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by ast_cdr_serialize_variables(), and cdr_read().

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

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

Definition at line 187 of file cdr.c.

References AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_name(), ast_var_value(), ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_cdr_getvar().

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

int ast_cdr_init ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

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

Definition at line 817 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_uniqueid(), ast_bridge_call(), ast_channel_alloc(), ast_feature_request_and_dial(), ast_pbx_outgoing_app_uniqueid(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

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

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

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

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

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

int ast_cdr_register ( const char *  name,
const char *  desc,
ast_cdrbe  be 
)

Register a CDR driver. Each registered CDR driver generates a CDR

Returns:
0 on success, -1 on failure

Definition at line 109 of file cdr.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), 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().

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

void ast_cdr_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

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

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

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

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

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

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

Definition at line 898 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_uniqueid(), ast_pbx_outgoing_app_uniqueid(), ast_pbx_outgoing_exten_uniqueid(), auth_exec(), cdr_write(), and rpt_call().

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

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

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

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

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

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

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

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

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

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

Referenced by ast_set_callerid().

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

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

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

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

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

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

int ast_cdr_setvar ( struct ast_cdr cdr,
const char *  name,
const char *  value,
int  recur 
)

Set a CDR channel variable

Note:
You can't set the CDR variables that belong to the actual CDR record, like "billsec".

Definition at line 293 of file cdr.c.

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

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

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 681 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_uniqueid(), ast_bridge_call(), ast_cdr_reset(), ast_channel_alloc(), ast_feature_request_and_dial(), ast_pbx_outgoing_app_uniqueid(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

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

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

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

void ast_cdr_unregister ( const char *  name  ) 

unregister a CDR driver

Definition at line 147 of file cdr.c.

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

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

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

int ast_cdr_update ( struct ast_channel c  ) 

Definition at line 952 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_uniqueid(), ast_feature_request_and_dial(), ast_parseable_goto(), cb_events(), clear_caller(), findmeexec(), and local_call().

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

static AST_LIST_HEAD_STATIC ( be_list  ,
ast_cdr_beitem   
) [static]

AST_MUTEX_DEFINE_STATIC ( cdr_pending_lock   ) 

AST_MUTEX_DEFINE_STATIC ( cdr_batch_lock   ) 

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

Definition at line 204 of file cdr.c.

References ast_localtime(), and t.

Referenced by ast_cdr_getvar().

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

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

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

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

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

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

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

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

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

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

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

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

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

static int do_reload ( void   )  [static]

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

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

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

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

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

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

Definition at line 1280 of file cdr.c.

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

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

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1077 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

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

static void post_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 985 of file cdr.c.

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

Referenced by ast_cdr_detach(), and do_batch_backend_process().

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

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

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

01070 {
01071    batch->size = 0;
01072    batch->head = NULL;
01073    batch->tail = NULL;
01074 }

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

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

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

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

Definition at line 1141 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

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

static void submit_unscheduled_batch ( void   )  [static]

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

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


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

Referenced by ast_cdr_engine_init(), and dnsmgr_init().

struct ast_cli_entry cli_submit [static]

Definition at line 1291 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 do_reload(), handle_cli_status(), and post_cdr().


Generated on Thu Oct 8 21:56:12 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6