Sat Aug 6 00:39:40 2011

Asterisk developer's documentation


cdr.c File Reference

Call Detail Record API. More...

#include "asterisk.h"
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/logger.h"
#include "asterisk/callerid.h"
#include "asterisk/causes.h"
#include "asterisk/options.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.h"
#include "asterisk/sched.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"

Go to the source code of this file.

Data Structures

struct  ast_cdr_batch
struct  ast_cdr_batch_item
struct  ast_cdr_beitem
struct  be_list

Defines

#define BATCH_SAFE_SHUTDOWN_DEFAULT   1
#define BATCH_SCHEDULER_ONLY_DEFAULT   0
#define BATCH_SIZE_DEFAULT   100
#define BATCH_TIME_DEFAULT   300

Functions

ast_cdrast_cdr_alloc (void)
 Allocate a CDR record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).
int ast_cdr_amaflags2int (const char *flag)
void ast_cdr_answer (struct ast_cdr *cdr)
ast_cdrast_cdr_append (struct ast_cdr *cdr, struct ast_cdr *newcdr)
int ast_cdr_appenduserfield (struct ast_channel *chan, const char *userfield)
void ast_cdr_busy (struct ast_cdr *cdr)
int ast_cdr_copy_vars (struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
void ast_cdr_detach (struct ast_cdr *cdr)
void ast_cdr_discard (struct ast_cdr *cdr)
 Discard and free a CDR record.
char * ast_cdr_disp2str (int disposition)
int ast_cdr_disposition (struct ast_cdr *cdr, int cause)
ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).
void ast_cdr_end (struct ast_cdr *cdr)
int ast_cdr_engine_init (void)
int ast_cdr_engine_reload (void)
void ast_cdr_engine_term (void)
void ast_cdr_failed (struct ast_cdr *cdr)
char * ast_cdr_flags2str (int flag)
void ast_cdr_free (struct ast_cdr *cdr)
 Free a CDR record.
void ast_cdr_free_vars (struct ast_cdr *cdr, int recur)
void ast_cdr_getvar (struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw)
static const char * ast_cdr_getvar_internal (struct ast_cdr *cdr, const char *name, int recur)
int ast_cdr_init (struct ast_cdr *cdr, struct ast_channel *c)
 Initialize based on a channel.
int ast_cdr_isset_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_setanswer (struct ast_cdr *cdr, struct timeval t)
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)
void ast_cdr_setdisposition (struct ast_cdr *cdr, long int disposition)
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_specialized_reset (struct ast_cdr *cdr, struct ast_flags *_flags)
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 void cdr_get_tv (struct timeval tv, const char *fmt, char *buf, int bufsize)
static void cdr_merge_vars (struct ast_cdr *to, struct ast_cdr *from)
int check_cdr_enabled ()
 Return TRUE if CDR subsystem is enabled.
static void check_post (struct ast_cdr *cdr)
 print a warning if cdr already posted
static void * do_batch_backend_process (void *data)
static void * do_cdr (void *data)
static int do_reload (void)
static int handle_cli_status (int fd, int argc, char *argv[])
static int handle_cli_submit (int fd, int argc, char *argv[])
static int init_batch (void)
static void post_cdr (struct ast_cdr *cdr)
static void reset_batch (void)
static void set_one_cid (struct ast_cdr *cdr, struct ast_channel *c)
static int submit_scheduled_batch (const void *data)
static void submit_unscheduled_batch (void)

Variables

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


Detailed Description

Call Detail Record API.

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

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

Definition in file cdr.c.


Define Documentation

#define BATCH_SAFE_SHUTDOWN_DEFAULT   1

Definition at line 89 of file cdr.c.

Referenced by do_reload().

#define BATCH_SCHEDULER_ONLY_DEFAULT   0

Definition at line 88 of file cdr.c.

Referenced by do_reload().

#define BATCH_SIZE_DEFAULT   100

Definition at line 86 of file cdr.c.

Referenced by do_reload().

#define BATCH_TIME_DEFAULT   300

Definition at line 87 of file cdr.c.

Referenced by do_reload().


Function Documentation

struct ast_cdr* ast_cdr_alloc ( void   ) 

Allocate a CDR record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).

Definition at line 469 of file cdr.c.

References ast_calloc, ast_log(), and LOG_ERROR.

Referenced by __agent_start_monitoring(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_dup(), builtin_blindtransfer(), clear_caller(), findmeexec(), and start_monitor_exec().

00470 {
00471    struct ast_cdr *x = ast_calloc(1, sizeof(struct ast_cdr));
00472    if (!x)
00473       ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
00474    return x;
00475 }

int ast_cdr_amaflags2int ( const char *  flag  ) 

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

Definition at line 1020 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_dahdi(), and set_config().

01021 {
01022    if (!strcasecmp(flag, "default"))
01023       return 0;
01024    if (!strcasecmp(flag, "omit"))
01025       return AST_CDR_OMIT;
01026    if (!strcasecmp(flag, "billing"))
01027       return AST_CDR_BILLING;
01028    if (!strcasecmp(flag, "documentation"))
01029       return AST_CDR_DOCUMENTATION;
01030    return -1;
01031 }

void ast_cdr_answer ( struct ast_cdr cdr  ) 

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

Definition at line 705 of file cdr.c.

References AST_CDR_ANSWERED, AST_CDR_FLAG_ANSLOCKED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_test_flag, ast_tvnow(), ast_tvzero(), check_post(), and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_answer(), and ast_bridge_call().

00706 {
00707 
00708    for (; cdr; cdr = cdr->next) {
00709       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED)) 
00710          continue;
00711       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00712          continue;
00713       check_post(cdr);
00714       if (cdr->disposition < AST_CDR_ANSWERED)
00715          cdr->disposition = AST_CDR_ANSWERED;
00716       if (ast_tvzero(cdr->answer))
00717          cdr->answer = ast_tvnow();
00718    }
00719 }

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

Definition at line 1131 of file cdr.c.

References ast_cdr::next.

Referenced by ast_cdr_fork(), and ast_cdr_merge().

01132 {
01133    struct ast_cdr *ret;
01134 
01135    if (cdr) {
01136       ret = cdr;
01137 
01138       while (cdr->next)
01139          cdr = cdr->next;
01140       cdr->next = newcdr;
01141    } else {
01142       ret = newcdr;
01143    }
01144 
01145    return ret;
01146 }

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

Definition at line 986 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, len(), ast_cdr::next, and ast_cdr::userfield.

Referenced by action_setcdruserfield(), and appendcdruserfield_exec().

00987 {
00988    struct ast_cdr *cdr = chan->cdr;
00989 
00990    for ( ; cdr ; cdr = cdr->next) {
00991       int len = strlen(cdr->userfield);
00992 
00993       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00994          ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
00995    }
00996 
00997    return 0;
00998 }

void ast_cdr_busy ( struct ast_cdr cdr  ) 

Parameters:
cdr the cdr you wish to associate with the call Marks the channel disposition as "BUSY" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application. Returns nothing

Definition at line 721 of file cdr.c.

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

Referenced by __ast_request_and_dial(), ast_cdr_disposition(), pbx_builtin_busy(), and ring_entry().

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

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

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

void ast_cdr_detach ( struct ast_cdr cdr  ) 

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

Definition at line 1242 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, cdr_batch_lock, 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_bridge_call(), ast_cdr_reset(), ast_hangup(), and ast_pbx_outgoing_cdr_failed().

01243 {
01244    struct ast_cdr_batch_item *newtail;
01245    int curr;
01246 
01247    if (!cdr)
01248       return;
01249 
01250    /* maybe they disabled CDR stuff completely, so just drop it */
01251    if (!enabled) {
01252       if (option_debug)
01253          ast_log(LOG_DEBUG, "Dropping CDR !\n");
01254       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01255       ast_cdr_free(cdr);
01256       return;
01257    }
01258 
01259    /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
01260    if (!batchmode) {
01261       post_cdr(cdr);
01262       ast_cdr_free(cdr);
01263       return;
01264    }
01265 
01266    /* otherwise, each CDR gets put into a batch list (at the end) */
01267    if (option_debug)
01268       ast_log(LOG_DEBUG, "CDR detaching from this thread\n");
01269 
01270    /* we'll need a new tail for every CDR */
01271    if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
01272       post_cdr(cdr);
01273       ast_cdr_free(cdr);
01274       return;
01275    }
01276 
01277    /* don't traverse a whole list (just keep track of the tail) */
01278    ast_mutex_lock(&cdr_batch_lock);
01279    if (!batch)
01280       init_batch();
01281    if (!batch->head) {
01282       /* new batch is empty, so point the head at the new tail */
01283       batch->head = newtail;
01284    } else {
01285       /* already got a batch with something in it, so just append a new tail */
01286       batch->tail->next = newtail;
01287    }
01288    newtail->cdr = cdr;
01289    batch->tail = newtail;
01290    curr = batch->size++;
01291    ast_mutex_unlock(&cdr_batch_lock);
01292 
01293    /* if we have enough stuff to post, then do it */
01294    if (curr >= (batchsize - 1))
01295       submit_unscheduled_batch();
01296 }

void ast_cdr_discard ( struct ast_cdr cdr  ) 

Discard and free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing -- same as free, but no checks or complaints

Definition at line 458 of file cdr.c.

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

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

00459 {
00460    while (cdr) {
00461       struct ast_cdr *next = cdr->next;
00462 
00463       ast_cdr_free_vars(cdr, 0);
00464       free(cdr);
00465       cdr = next;
00466    }
00467 }

char* ast_cdr_disp2str ( int  disposition  ) 

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

Definition at line 915 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_query(), build_radius_record(), csv_log(), manager_log(), pgsql_log(), and tds_log().

00916 {
00917    switch (disposition) {
00918    case AST_CDR_NULL:
00919       return "NO ANSWER"; /* by default, for backward compatibility */
00920    case AST_CDR_NOANSWER:
00921       return "NO ANSWER";
00922    case AST_CDR_FAILED:
00923       return "FAILED";     
00924    case AST_CDR_BUSY:
00925       return "BUSY";    
00926    case AST_CDR_ANSWERED:
00927       return "ANSWERED";
00928    }
00929    return "UNKNOWN";
00930 }

int ast_cdr_disposition ( struct ast_cdr cdr,
int  cause 
)

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

Definition at line 760 of file cdr.c.

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

Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), clear_caller(), and findmeexec().

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

struct ast_cdr* ast_cdr_dup ( struct ast_cdr cdr  ) 

Duplicate a record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 177 of file cdr.c.

References ast_cdr_alloc(), and ast_cdr_copy_vars().

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

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

void ast_cdr_end ( struct ast_cdr cdr  ) 

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

Definition at line 892 of file cdr.c.

References AST_CDR_ANSWERED, AST_CDR_FAILED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_log(), ast_test_flag, ast_tvnow(), ast_tvzero(), check_post(), LOG_WARNING, ast_cdr::next, and S_OR.

Referenced by __ast_request_and_dial(), ast_bridge_call(), ast_cdr_fork(), ast_cdr_reset(), ast_hangup(), ast_pbx_outgoing_cdr_failed(), clear_caller(), and findmeexec().

00893 {
00894    for ( ; cdr ; cdr = cdr->next) {
00895       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00896          continue;
00897       check_post(cdr);
00898       if (ast_tvzero(cdr->end))
00899          cdr->end = ast_tvnow();
00900       if (ast_tvzero(cdr->start)) {
00901          ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
00902          cdr->disposition = AST_CDR_FAILED;
00903       } else
00904          cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
00905       if (ast_tvzero(cdr->answer)) {
00906          if (cdr->disposition == AST_CDR_ANSWERED) {
00907             ast_log(LOG_WARNING, "CDR on channel '%s' has no answer time but is 'ANSWERED'\n", S_OR(cdr->channel, "<unknown>"));
00908             cdr->disposition = AST_CDR_FAILED;
00909          }
00910       } else
00911          cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec;
00912    }
00913 }

int ast_cdr_engine_init ( void   ) 

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

Definition at line 1500 of file cdr.c.

References ast_cli_register(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), cdr_batch_lock, cli_status, do_reload(), init_batch(), LOG_ERROR, and sched_context_create().

Referenced by main().

01501 {
01502    int res;
01503 
01504    sched = sched_context_create();
01505    if (!sched) {
01506       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
01507       return -1;
01508    }
01509 
01510    ast_cli_register(&cli_status);
01511 
01512    res = do_reload();
01513    if (res) {
01514       ast_mutex_lock(&cdr_batch_lock);
01515       res = init_batch();
01516       ast_mutex_unlock(&cdr_batch_lock);
01517    }
01518 
01519    return res;
01520 }

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1529 of file cdr.c.

References do_reload().

01530 {
01531    return do_reload();
01532 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1524 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01525 {
01526    ast_cdr_submit_batch(batchsafeshutdown);
01527 }

void ast_cdr_failed ( struct ast_cdr cdr  ) 

Parameters:
cdr the cdr you wish to associate with the call Marks the channel disposition as "FAILED" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application. Returns nothing

Definition at line 732 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_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten(), clear_caller(), findmeexec(), and wait_for_answer().

00733 {
00734    for (; cdr; cdr = cdr->next) {
00735       check_post(cdr);
00736       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00737          if (cdr->disposition < AST_CDR_FAILED)
00738             cdr->disposition = AST_CDR_FAILED;
00739       }
00740    }
00741 }

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

00934 {
00935    switch(flag) {
00936    case AST_CDR_OMIT:
00937       return "OMIT";
00938    case AST_CDR_BILLING:
00939       return "BILLING";
00940    case AST_CDR_DOCUMENTATION:
00941       return "DOCUMENTATION";
00942    }
00943    return "Unknown";
00944 }

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

Definition at line 438 of file cdr.c.

References AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, ast_cdr_free_vars(), ast_test_flag, ast_tvzero(), ast_verbose(), ast_cdr::channel, ast_cdr::end, free, ast_cdr_beitem::next, ast_cdr::next, option_verbose, S_OR, ast_cdr::start, and VERBOSE_PREFIX_2.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

00439 {
00440 
00441    while (cdr) {
00442       struct ast_cdr *next = cdr->next;
00443       char *chan = S_OR(cdr->channel, "<unknown>");
00444       if (option_verbose > 1 && !ast_test_flag(cdr, AST_CDR_FLAG_POSTED) && !ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
00445          ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' not posted\n", chan);
00446       if (option_verbose > 1 && ast_tvzero(cdr->end))
00447          ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' lacks end\n", chan);
00448       if (option_verbose > 1 && ast_tvzero(cdr->start))
00449          ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' lacks start\n", chan);
00450 
00451       ast_cdr_free_vars(cdr, 0);
00452       free(cdr);
00453       cdr = next;
00454    }
00455 }

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

00418 {
00419 
00420    /* clear variables */
00421    for (; cdr; cdr = recur ? cdr->next : NULL) {
00422       struct ast_var_t *vardata;
00423       struct varshead *headp = &cdr->varshead;
00424       while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
00425          ast_var_delete(vardata);
00426    }
00427 }

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

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

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

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

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

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

References ast_channel::_state, ast_channel::accountcode, ast_channel::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_copy_string(), AST_STATE_UP, ast_test_flag, ast_cdr::channel, ast_channel::context, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::name, ast_cdr::next, S_OR, set_one_cid(), and ast_channel::uniqueid.

Referenced by __ast_request_and_dial(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

00858 {
00859    char *chan;
00860 
00861    for ( ; cdr ; cdr = cdr->next) {
00862       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00863          chan = S_OR(cdr->channel, "<unknown>");
00864          ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
00865          set_one_cid(cdr, c);
00866 
00867          cdr->disposition = (c->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
00868          cdr->amaflags = c->amaflags ? c->amaflags :  ast_default_amaflags;
00869          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00870          /* Destination information */
00871          ast_copy_string(cdr->dst, S_OR(c->macroexten,c->exten), sizeof(cdr->dst));
00872          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext,c->context), sizeof(cdr->dcontext));
00873          /* Unique call identifier */
00874          ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid));
00875       }
00876    }
00877    return 0;
00878 }

int ast_cdr_isset_unanswered ( void   ) 

Definition at line 169 of file cdr.c.

References unanswered.

Referenced by ring_entry(), and try_calling().

00170 {
00171    return unanswered;
00172 }

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 513 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_copy_string(), ast_log(), ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_tv(), ast_tvcmp(), ast_tvzero(), 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.

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

void ast_cdr_noanswer ( struct ast_cdr cdr  ) 

Parameters:
cdr the cdr you wish to associate with the call Marks the channel disposition as "NO ANSWER" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application.

Definition at line 743 of file cdr.c.

References AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_strlen_zero(), ast_test_flag, ast_cdr::channel, check_post(), ast_cdr::disposition, and ast_cdr::next.

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

00744 {
00745    char *chan; 
00746 
00747    while (cdr) {
00748       chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
00749       check_post(cdr);
00750       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00751          cdr->disposition = AST_CDR_NOANSWER;
00752       }
00753       cdr = cdr->next;
00754    }
00755 }

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

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

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

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

void ast_cdr_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

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

Definition at line 1070 of file cdr.c.

References ast_cdr::answer, ast_cdr_detach(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POSTED, ast_cdr_free_vars(), AST_CDR_NOANSWER, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, ast_flags::flags, ast_cdr::next, and ast_cdr::start.

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

01071 {
01072    struct ast_cdr *dup;
01073    struct ast_flags flags = { 0 };
01074 
01075    if (_flags)
01076       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
01077 
01078    for ( ; cdr ; cdr = cdr->next) {
01079       /* Detach if post is requested */
01080       if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01081          if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
01082             ast_cdr_end(cdr);
01083             if ((dup = ast_cdr_dup(cdr))) {
01084                ast_cdr_detach(dup);
01085             }
01086             ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
01087          }
01088 
01089          /* clear variables */
01090          if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
01091             ast_cdr_free_vars(cdr, 0);
01092          }
01093 
01094          /* Reset to initial state */
01095          ast_clear_flag(cdr, AST_FLAGS_ALL); 
01096          memset(&cdr->start, 0, sizeof(cdr->start));
01097          memset(&cdr->end, 0, sizeof(cdr->end));
01098          memset(&cdr->answer, 0, sizeof(cdr->answer));
01099          cdr->billsec = 0;
01100          cdr->duration = 0;
01101          ast_cdr_start(cdr);
01102          cdr->disposition = AST_CDR_NOANSWER;
01103       }
01104    }
01105 }

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

Definition at line 372 of file cdr.c.

References ast_build_string(), ast_cdr_getvar(), AST_LIST_TRAVERSE, ast_log(), ast_var_name(), ast_var_value(), cdr_readonly_vars, ast_var_t::entries, LOG_ERROR, ast_cdr::next, S_OR, total, var, and ast_cdr::varshead.

Referenced by handle_showchan(), and handle_showchan_deprecated().

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

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

Definition at line 946 of file cdr.c.

References accountcode, ast_cdr::accountcode, ast_channel::accountcode, AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_string_field_set, ast_test_flag, ast_channel::cdr, and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_bridge_call(), ast_call_forward(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), auth_exec(), cdr_write(), and rpt_call().

00947 {
00948    struct ast_cdr *cdr = chan->cdr;
00949 
00950    ast_string_field_set(chan, accountcode, account);
00951    for ( ; cdr ; cdr = cdr->next) {
00952       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00953          ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode));
00954       }
00955    }
00956    return 0;
00957 }

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

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

00960 {
00961    struct ast_cdr *cdr;
00962    int newflag = ast_cdr_amaflags2int(flag);
00963    if (newflag) {
00964       for (cdr = chan->cdr; cdr; cdr = cdr->next) {
00965          if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00966             cdr->amaflags = newflag;
00967          }
00968       }
00969    }
00970 
00971    return 0;
00972 }

void ast_cdr_setanswer ( struct ast_cdr cdr,
struct timeval  t 
)

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

Definition at line 803 of file cdr.c.

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

Referenced by ast_bridge_call().

00804 {
00805 
00806    for (; cdr; cdr = cdr->next) {
00807       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
00808          continue;
00809       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00810          continue;
00811       check_post(cdr);
00812       cdr->answer = t;
00813    }
00814 }

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

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

Definition at line 791 of file cdr.c.

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

Referenced by __ast_request_and_dial(), agi_handle_command(), clear_caller(), findmeexec(), and pbx_exec().

00792 {
00793 
00794    for (; cdr; cdr = cdr->next) {
00795       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00796          check_post(cdr);
00797          ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp));
00798          ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata));
00799       }
00800    }
00801 }

int ast_cdr_setcid ( struct ast_cdr cdr,
struct ast_channel chan 
)

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

Definition at line 848 of file cdr.c.

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

Referenced by ast_bridge_call(), ast_set_callerid(), and callerid_write().

00849 {
00850    for (; cdr; cdr = cdr->next) {
00851       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00852          set_one_cid(cdr, c);
00853    }
00854    return 0;
00855 }

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

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

Definition at line 782 of file cdr.c.

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

Referenced by park_exec(), and ring_entry().

00783 {
00784    for (; cdr; cdr = cdr->next) {
00785       check_post(cdr);
00786       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00787          ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
00788    }
00789 }

void ast_cdr_setdisposition ( struct ast_cdr cdr,
long int  disposition 
)

Parameters:
cdr the cdr you wish to associate with the call
disposition the new disposition Set the disposition on a call. NULL argument is just fine.

Definition at line 816 of file cdr.c.

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

Referenced by ast_bridge_call().

00817 {
00818 
00819    for (; cdr; cdr = cdr->next) {
00820       if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00821          continue;
00822       check_post(cdr);
00823       cdr->disposition = disposition;
00824    }
00825 }

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

Definition at line 974 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, ast_cdr::next, and ast_cdr::userfield.

Referenced by __agent_start_monitoring(), action_setcdruserfield(), cdr_write(), handle_request_info(), setcdruserfield_exec(), and start_monitor_exec().

00975 {
00976    struct ast_cdr *cdr = chan->cdr;
00977 
00978    for ( ; cdr ; cdr = cdr->next) {
00979       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 
00980          ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
00981    }
00982 
00983    return 0;
00984 }

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

References AST_CDR_FLAG_DONT_TOUCH, 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, and ast_cdr::next.

Referenced by ast_cdr_fork(), cdr_write(), and set_one_cid().

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

void ast_cdr_specialized_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

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

Definition at line 1107 of file cdr.c.

References ast_cdr::answer, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, ast_flags::flags, and ast_cdr::start.

Referenced by ast_bridge_call().

01108 {
01109    struct ast_flags flags = { 0 };
01110 
01111    if (_flags)
01112       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
01113    
01114    /* Reset to initial state */
01115    if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) { /* But do NOT lose the NoCDR() setting */
01116       ast_clear_flag(cdr, AST_FLAGS_ALL); 
01117       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01118    } else {
01119       ast_clear_flag(cdr, AST_FLAGS_ALL); 
01120    }
01121    
01122    memset(&cdr->start, 0, sizeof(cdr->start));
01123    memset(&cdr->end, 0, sizeof(cdr->end));
01124    memset(&cdr->answer, 0, sizeof(cdr->answer));
01125    cdr->billsec = 0;
01126    cdr->duration = 0;
01127    ast_cdr_start(cdr);
01128    cdr->disposition = AST_CDR_NULL;
01129 }

void ast_cdr_start ( struct ast_cdr cdr  ) 

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

Definition at line 692 of file cdr.c.

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

Referenced by __ast_request_and_dial(), ast_bridge_call(), ast_cdr_reset(), ast_cdr_specialized_reset(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

00693 {
00694    char *chan; 
00695 
00696    for (; cdr; cdr = cdr->next) {
00697       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00698          chan = S_OR(cdr->channel, "<unknown>");
00699          check_post(cdr);
00700          cdr->start = ast_tvnow();
00701       }
00702    }
00703 }

void ast_cdr_submit_batch ( int  shutdown  ) 

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

Definition at line 1185 of file cdr.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, batch, batchscheduleronly, cdr_batch_lock, 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().

01186 {
01187    struct ast_cdr_batch_item *oldbatchitems = NULL;
01188    pthread_attr_t attr;
01189    pthread_t batch_post_thread = AST_PTHREADT_NULL;
01190 
01191    /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
01192    if (!batch || !batch->head)
01193       return;
01194 
01195    /* move the old CDRs aside, and prepare a new CDR batch */
01196    ast_mutex_lock(&cdr_batch_lock);
01197    oldbatchitems = batch->head;
01198    reset_batch();
01199    ast_mutex_unlock(&cdr_batch_lock);
01200 
01201    /* if configured, spawn a new thread to post these CDRs,
01202       also try to save as much as possible if we are shutting down safely */
01203    if (batchscheduleronly || shutdown) {
01204       if (option_debug)
01205          ast_log(LOG_DEBUG, "CDR single-threaded batch processing begins now\n");
01206       do_batch_backend_process(oldbatchitems);
01207    } else {
01208       pthread_attr_init(&attr);
01209       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01210       if (ast_pthread_create_background(&batch_post_thread, &attr, do_batch_backend_process, oldbatchitems)) {
01211          ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
01212          do_batch_backend_process(oldbatchitems);
01213       } else {
01214          if (option_debug)
01215             ast_log(LOG_DEBUG, "CDR multi-threaded batch processing begins now\n");
01216       }
01217       pthread_attr_destroy(&attr);
01218    }
01219 }

void ast_cdr_unregister ( const char *  name  ) 

unregister a CDR driver

Definition at line 151 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::list, 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().

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

int ast_cdr_update ( struct ast_channel c  ) 

Definition at line 1000 of file cdr.c.

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

Referenced by __ast_pbx_run(), __ast_request_and_dial(), ast_bridge_call(), cb_events(), clear_caller(), findmeexec(), and local_call().

01001 {
01002    struct ast_cdr *cdr = c->cdr;
01003 
01004    for ( ; cdr ; cdr = cdr->next) {
01005       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01006          set_one_cid(cdr, c);
01007 
01008          /* Copy account code et-al */ 
01009          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
01010          
01011          /* Destination information */ /* XXX privilege macro* ? */
01012          ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst));
01013          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext));
01014       }
01015    }
01016 
01017    return 0;
01018 }

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

Definition at line 213 of file cdr.c.

References ast_localtime(), and t.

Referenced by ast_cdr_getvar().

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

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

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

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

int check_cdr_enabled ( void   ) 

Return TRUE if CDR subsystem is enabled.

Definition at line 105 of file cdr.c.

References enabled.

Referenced by action_coresettings(), and handle_show_settings().

00106 {
00107    return enabled;
00108 }

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

Definition at line 430 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_noanswer(), ast_cdr_setanswer(), ast_cdr_setapp(), ast_cdr_setdestchan(), ast_cdr_setdisposition(), ast_cdr_start(), and post_cdr().

00431 {
00432    if (!cdr)
00433       return;
00434    if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
00435       ast_log(LOG_NOTICE, "CDR on channel '%s' already posted\n", S_OR(cdr->channel, "<unknown>"));
00436 }

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

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

01169 {
01170    struct ast_cdr_batch_item *processeditem;
01171    struct ast_cdr_batch_item *batchitem = data;
01172 
01173    /* Push each CDR into storage mechanism(s) and free all the memory */
01174    while (batchitem) {
01175       post_cdr(batchitem->cdr);
01176       ast_cdr_free(batchitem->cdr);
01177       processeditem = batchitem;
01178       batchitem = batchitem->next;
01179       free(processeditem);
01180    }
01181 
01182    return NULL;
01183 }

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

Definition at line 1298 of file cdr.c.

References ast_cond_timedwait(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_samp2tv(), ast_sched_runq(), ast_sched_wait(), ast_tvadd(), ast_tvnow(), cdr_pending_cond, cdr_pending_lock, LOG_DEBUG, and option_debug.

Referenced by do_reload().

01299 {
01300    struct timespec timeout;
01301    int schedms;
01302    int numevents = 0;
01303 
01304    for(;;) {
01305       struct timeval now;
01306       schedms = ast_sched_wait(sched);
01307       /* this shouldn't happen, but provide a 1 second default just in case */
01308       if (schedms <= 0)
01309          schedms = 1000;
01310       now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
01311       timeout.tv_sec = now.tv_sec;
01312       timeout.tv_nsec = now.tv_usec * 1000;
01313       /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
01314       ast_mutex_lock(&cdr_pending_lock);
01315       ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
01316       numevents = ast_sched_runq(sched);
01317       ast_mutex_unlock(&cdr_pending_lock);
01318       if (option_debug > 1)
01319          ast_log(LOG_DEBUG, "Processed %d scheduled CDR batches from the run queue\n", numevents);
01320    }
01321 
01322    return NULL;
01323 }

static int do_reload ( void   )  [static]

Definition at line 1385 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_batch_lock, 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().

01386 {
01387    struct ast_config *config;
01388    const char *enabled_value;
01389    const char *unanswered_value;
01390    const char *batched_value;
01391    const char *scheduleronly_value;
01392    const char *batchsafeshutdown_value;
01393    const char *size_value;
01394    const char *time_value;
01395    const char *end_before_h_value;
01396    int cfg_size;
01397    int cfg_time;
01398    int was_enabled;
01399    int was_batchmode;
01400    int res=0;
01401 
01402    ast_mutex_lock(&cdr_batch_lock);
01403 
01404    batchsize = BATCH_SIZE_DEFAULT;
01405    batchtime = BATCH_TIME_DEFAULT;
01406    batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
01407    batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
01408    was_enabled = enabled;
01409    was_batchmode = batchmode;
01410    enabled = 1;
01411    batchmode = 0;
01412 
01413    /* don't run the next scheduled CDR posting while reloading */
01414    AST_SCHED_DEL(sched, cdr_sched);
01415 
01416    if ((config = ast_config_load("cdr.conf"))) {
01417       if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
01418          enabled = ast_true(enabled_value);
01419       }
01420       if ((unanswered_value = ast_variable_retrieve(config, "general", "unanswered"))) {
01421          unanswered = ast_true(unanswered_value);
01422       }
01423       if ((batched_value = ast_variable_retrieve(config, "general", "batch"))) {
01424          batchmode = ast_true(batched_value);
01425       }
01426       if ((scheduleronly_value = ast_variable_retrieve(config, "general", "scheduleronly"))) {
01427          batchscheduleronly = ast_true(scheduleronly_value);
01428       }
01429       if ((batchsafeshutdown_value = ast_variable_retrieve(config, "general", "safeshutdown"))) {
01430          batchsafeshutdown = ast_true(batchsafeshutdown_value);
01431       }
01432       if ((size_value = ast_variable_retrieve(config, "general", "size"))) {
01433          if (sscanf(size_value, "%30d", &cfg_size) < 1)
01434             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", size_value);
01435          else if (cfg_size < 0)
01436             ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
01437          else
01438             batchsize = cfg_size;
01439       }
01440       if ((time_value = ast_variable_retrieve(config, "general", "time"))) {
01441          if (sscanf(time_value, "%30d", &cfg_time) < 1)
01442             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", time_value);
01443          else if (cfg_time < 0)
01444             ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
01445          else
01446             batchtime = cfg_time;
01447       }
01448       if ((end_before_h_value = ast_variable_retrieve(config, "general", "endbeforehexten")))
01449          ast_set2_flag(&ast_options, ast_true(end_before_h_value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
01450    }
01451 
01452    if (enabled && !batchmode) {
01453       ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
01454    } else if (enabled && batchmode) {
01455       cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01456       ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
01457    } else {
01458       ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
01459    }
01460 
01461    /* if this reload enabled the CDR batch mode, create the background thread
01462       if it does not exist */
01463    if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
01464       ast_cond_init(&cdr_pending_cond, NULL);
01465       if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
01466          ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
01467          AST_SCHED_DEL(sched, cdr_sched);
01468       } else {
01469          ast_cli_register(&cli_submit);
01470          ast_register_atexit(ast_cdr_engine_term);
01471          res = 0;
01472       }
01473    /* if this reload disabled the CDR and/or batch mode and there is a background thread,
01474       kill it */
01475    } else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
01476       /* wake up the thread so it will exit */
01477       pthread_cancel(cdr_thread);
01478       pthread_kill(cdr_thread, SIGURG);
01479       pthread_join(cdr_thread, NULL);
01480       cdr_thread = AST_PTHREADT_NULL;
01481       ast_cond_destroy(&cdr_pending_cond);
01482       ast_cli_unregister(&cli_submit);
01483       ast_unregister_atexit(ast_cdr_engine_term);
01484       res = 0;
01485       /* if leaving batch mode, then post the CDRs in the batch,
01486          and don't reschedule, since we are stopping CDR logging */
01487       if (!batchmode && was_batchmode) {
01488          ast_cdr_engine_term();
01489       }
01490    } else {
01491       res = 0;
01492    }
01493 
01494    ast_mutex_unlock(&cdr_batch_lock);
01495    ast_config_destroy(config);
01496 
01497    return res;
01498 }

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

Definition at line 1325 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::list, ast_cdr_beitem::name, RESULT_SHOWUSAGE, and unanswered.

01326 {
01327    struct ast_cdr_beitem *beitem=NULL;
01328    int cnt=0;
01329    long nextbatchtime=0;
01330 
01331    if (argc > 2)
01332       return RESULT_SHOWUSAGE;
01333 
01334    ast_cli(fd, "CDR logging: %s\n", enabled ? "enabled" : "disabled");
01335    ast_cli(fd, "CDR mode: %s\n", batchmode ? "batch" : "simple");
01336    if (enabled) {
01337       ast_cli(fd, "CDR output unanswered calls: %s\n", unanswered ? "yes" : "no");
01338       if (batchmode) {
01339          if (batch)
01340             cnt = batch->size;
01341          if (cdr_sched > -1)
01342             nextbatchtime = ast_sched_when(sched, cdr_sched);
01343          ast_cli(fd, "CDR safe shut down: %s\n", batchsafeshutdown ? "enabled" : "disabled");
01344          ast_cli(fd, "CDR batch threading model: %s\n", batchscheduleronly ? "scheduler only" : "scheduler plus separate threads");
01345          ast_cli(fd, "CDR current batch size: %d record%s\n", cnt, (cnt != 1) ? "s" : "");
01346          ast_cli(fd, "CDR maximum batch size: %d record%s\n", batchsize, (batchsize != 1) ? "s" : "");
01347          ast_cli(fd, "CDR maximum batch time: %d second%s\n", batchtime, (batchtime != 1) ? "s" : "");
01348          ast_cli(fd, "CDR next scheduled batch processing time: %ld second%s\n", nextbatchtime, (nextbatchtime != 1) ? "s" : "");
01349       }
01350       AST_LIST_LOCK(&be_list);
01351       AST_LIST_TRAVERSE(&be_list, beitem, list) {
01352          ast_cli(fd, "CDR registered backend: %s\n", beitem->name);
01353       }
01354       AST_LIST_UNLOCK(&be_list);
01355    }
01356 
01357    return 0;
01358 }

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

Definition at line 1360 of file cdr.c.

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

01361 {
01362    if (argc > 2)
01363       return RESULT_SHOWUSAGE;
01364 
01365    submit_unscheduled_batch();
01366    ast_cli(fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
01367 
01368    return 0;
01369 }

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1157 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

01158 {
01159    /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
01160    if (!(batch = ast_malloc(sizeof(*batch))))
01161       return -1;
01162 
01163    reset_batch();
01164 
01165    return 0;
01166 }

static void post_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 1033 of file cdr.c.

References AST_CDR_ANSWERED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_ORIGINATED, AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_tvzero(), ast_verbose(), ast_cdr_beitem::be, ast_cdr::channel, check_post(), ast_cdr::disposition, ast_cdr::dstchannel, ast_cdr::end, ast_cdr_beitem::list, ast_cdr::next, option_verbose, S_OR, ast_cdr::start, unanswered, and VERBOSE_PREFIX_2.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

01034 {
01035    char *chan;
01036    struct ast_cdr_beitem *i;
01037 
01038    for ( ; cdr ; cdr = cdr->next) {
01039       if (!unanswered && !ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
01040          /* For people, who don't want to see unanswered single-channel events */
01041          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01042          continue;
01043       }
01044 
01045       /* don't post CDRs that are for dialed channels unless those
01046        * channels were originated from asterisk (pbx_spool, manager,
01047        * cli) */
01048       if (ast_test_flag(cdr, AST_CDR_FLAG_DIALED) && !ast_test_flag(cdr, AST_CDR_FLAG_ORIGINATED)) {
01049          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01050          continue;
01051       }
01052 
01053       chan = S_OR(cdr->channel, "<unknown>");
01054       check_post(cdr);
01055       if (option_verbose > 1 && ast_tvzero(cdr->end))
01056          ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' lacks end\n", chan);
01057       if (option_verbose > 1 && ast_tvzero(cdr->start))
01058          ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' lacks start\n", chan);
01059       ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
01060       if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
01061          continue;
01062       AST_LIST_LOCK(&be_list);
01063       AST_LIST_TRAVERSE(&be_list, i, list) {
01064          i->be(cdr);
01065       }
01066       AST_LIST_UNLOCK(&be_list);
01067    }
01068 }

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

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

01150 {
01151    batch->size = 0;
01152    batch->head = NULL;
01153    batch->tail = NULL;
01154 }

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

Definition at line 828 of file cdr.c.

References ast_cdr_setvar(), ast_copy_string(), ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_dnid, 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().

00829 {
00830    /* Grab source from ANI or normal Caller*ID */
00831    const char *num = S_OR(c->cid.cid_ani, c->cid.cid_num);
00832    if (!cdr)
00833       return;
00834    if (!ast_strlen_zero(c->cid.cid_name)) {
00835       if (!ast_strlen_zero(num)) /* both name and number */
00836          snprintf(cdr->clid, sizeof(cdr->clid), "\"%s\" <%s>", c->cid.cid_name, num);
00837       else           /* only name */
00838          ast_copy_string(cdr->clid, c->cid.cid_name, sizeof(cdr->clid));
00839    } else if (!ast_strlen_zero(num)) { /* only number */
00840       ast_copy_string(cdr->clid, num, sizeof(cdr->clid));
00841    } else {          /* nothing known */
00842       cdr->clid[0] = '\0';
00843    }
00844    ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src));
00845    ast_cdr_setvar(cdr, "dnid", S_OR(c->cid.cid_dnid, ""), 0);
00846 
00847 }

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

Definition at line 1221 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

01222 {
01223    ast_cdr_submit_batch(0);
01224    /* manually reschedule from this point in time */
01225    cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01226    /* returning zero so the scheduler does not automatically reschedule */
01227    return 0;
01228 }

static void submit_unscheduled_batch ( void   )  [static]

Definition at line 1230 of file cdr.c.

References ast_cond_signal(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_add(), AST_SCHED_DEL, cdr_pending_cond, cdr_pending_lock, cdr_sched, and submit_scheduled_batch().

Referenced by ast_cdr_detach(), and handle_cli_submit().

01231 {
01232    /* this is okay since we are not being called from within the scheduler */
01233    AST_SCHED_DEL(sched, cdr_sched);
01234    /* schedule the submission to occur ASAP (1 ms) */
01235    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
01236    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
01237    ast_mutex_lock(&cdr_pending_lock);
01238    ast_cond_signal(&cdr_pending_cond);
01239    ast_mutex_unlock(&cdr_pending_lock);
01240 }


Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]

Definition at line 60 of file cdr.c.

int ast_default_amaflags = AST_CDR_DOCUMENTATION

Default AMA flag for billing records (CDR's)

Definition at line 59 of file cdr.c.

Referenced by ast_bridge_call().

struct ast_cdr_batch * batch [static]

Referenced by ast_cdr_detach(), ast_cdr_submit_batch(), handle_cli_status(), init_batch(), and reset_batch().

int batchmode [static]

Definition at line 93 of file cdr.c.

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

int batchsafeshutdown [static]

Definition at line 97 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 96 of file cdr.c.

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

int batchsize [static]

Definition at line 94 of file cdr.c.

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

int batchtime [static]

Definition at line 95 of file cdr.c.

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

ast_mutex_t cdr_batch_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

Definition at line 99 of file cdr.c.

Referenced by ast_cdr_detach(), ast_cdr_engine_init(), ast_cdr_submit_batch(), and do_reload().

ast_cond_t cdr_pending_cond [static]

Definition at line 103 of file cdr.c.

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

ast_mutex_t cdr_pending_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

Definition at line 102 of file cdr.c.

Referenced by do_cdr(), 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 295 of file cdr.c.

Referenced by ast_cdr_serialize_variables(), and ast_cdr_setvar().

int cdr_sched = -1 [static]

Definition at line 83 of file cdr.c.

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

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 84 of file cdr.c.

Referenced by do_reload().

struct ast_cli_entry cli_status [static]

Definition at line 1378 of file cdr.c.

Referenced by ast_cdr_engine_init(), and dnsmgr_init().

struct ast_cli_entry cli_submit [static]

Definition at line 1371 of file cdr.c.

Referenced by do_reload().

int enabled [static]

Definition at line 91 of file cdr.c.

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

struct sched_context* sched [static]

Definition at line 82 of file cdr.c.

Referenced by __attempt_transmit(), __find_callno(), __iax2_poke_noanswer(), __oh323_destroy(), __oh323_rtp_create(), __oh323_update_info(), __send_lagrq(), __send_ping(), __sip_ack(), __sip_destroy(), __sip_reliable_xmit(), __sip_semi_ack(), __unload_module(), _sip_show_peer(), ack_trans(), ast_rtp_new(), ast_rtp_new_with_bindaddr(), ast_udptl_new(), ast_udptl_new_with_bindaddr(), auth_fail(), build_peer(), delete_users(), destroy_packet(), destroy_packets(), destroy_peer(), dnsmgr_init(), dnsmgr_start_refresh(), do_monitor(), do_refresh(), do_register(), do_reload(), dundi_discover(), dundi_query(), dundi_send(), handle_command_response(), handle_request_cancel(), handle_response_invite(), handle_response_peerpoke(), handle_response_register(), iax2_ack_registry(), iax2_call(), iax2_destroy(), iax2_destroy_helper(), iax2_do_register(), iax2_dprequest(), iax2_frame_free(), iax2_hangup(), iax2_poke_peer(), iax2_provision(), load_module(), make_trunk(), network_thread(), parse_register_contact(), populate_addr(), precache_trans(), qualify_peer(), queue_request(), reg_source_db(), remove_provisional_keepalive_sched(), sched_delay_remove(), sched_thread(), schedule_delivery(), sip_alloc(), sip_call(), sip_cancel_destroy(), sip_do_reload(), sip_hangup(), sip_poke_all_peers(), sip_poke_noanswer(), sip_poke_peer(), sip_registry_destroy(), sip_scheddestroy(), sip_send_all_registers(), sipsock_read(), socket_process(), transmit_register(), unlink_peer(), unload_module(), update_jbsched(), update_provisional_keepalive(), and update_registry().

int unanswered [static]

Is the CDR subsystem enabled ?

Definition at line 92 of file cdr.c.

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


Generated on Sat Aug 6 00:39:40 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7