Thu Oct 11 06:42:54 2012

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
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

struct ast_cdrast_cdr_alloc (void)
 Allocate a CDR record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).
int ast_cdr_amaflags2int (const char *flag)
void ast_cdr_answer (struct ast_cdr *cdr)
struct ast_cdrast_cdr_append (struct ast_cdr *cdr, struct ast_cdr *newcdr)
int ast_cdr_appenduserfield (struct ast_channel *chan, const char *userfield)
void ast_cdr_busy (struct ast_cdr *cdr)
int ast_cdr_copy_vars (struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
void ast_cdr_detach (struct ast_cdr *cdr)
void ast_cdr_discard (struct ast_cdr *cdr)
 the same as a cdr_free call, only with no checks; just get rid of it
char * ast_cdr_disp2str (int disposition)
int ast_cdr_disposition (struct ast_cdr *cdr, int cause)
struct ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).
void ast_cdr_end (struct ast_cdr *cdr)
int ast_cdr_engine_init (void)
int ast_cdr_engine_reload (void)
void ast_cdr_engine_term (void)
void ast_cdr_failed (struct ast_cdr *cdr)
char * ast_cdr_flags2str (int flag)
void ast_cdr_free (struct ast_cdr *cdr)
 Free a CDR record.
void ast_cdr_free_vars (struct ast_cdr *cdr, int recur)
void ast_cdr_getvar (struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw)
static const char * ast_cdr_getvar_internal (struct ast_cdr *cdr, const char *name, int recur)
int ast_cdr_init (struct ast_cdr *cdr, struct ast_channel *c)
 Initialize based on a channel.
int ast_cdr_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)
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   )  [read]

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

Definition at line 465 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(), ast_channel_alloc(), builtin_blindtransfer(), clear_caller(), findmeexec(), and start_monitor_exec().

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

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

01017 {
01018    if (!strcasecmp(flag, "default"))
01019       return 0;
01020    if (!strcasecmp(flag, "omit"))
01021       return AST_CDR_OMIT;
01022    if (!strcasecmp(flag, "billing"))
01023       return AST_CDR_BILLING;
01024    if (!strcasecmp(flag, "documentation"))
01025       return AST_CDR_DOCUMENTATION;
01026    return -1;
01027 }

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

References ast_cdr::answer, 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(), ast_cdr::disposition, and ast_cdr::next.

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

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

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

Definition at line 1127 of file cdr.c.

References ast_cdr::next.

Referenced by ast_cdr_fork(), and ast_cdr_merge().

01128 {
01129    struct ast_cdr *ret;
01130 
01131    if (cdr) {
01132       ret = cdr;
01133 
01134       while (cdr->next)
01135          cdr = cdr->next;
01136       cdr->next = newcdr;
01137    } else {
01138       ret = newcdr;
01139    }
01140 
01141    return ret;
01142 }

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

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

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

void ast_cdr_busy ( struct ast_cdr cdr  ) 

Busy a call

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 717 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_request_and_dial(), ast_cdr_disposition(), pbx_builtin_busy(), ring_entry(), and wait_for_answer().

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

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

Definition at line 342 of file cdr.c.

References AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_assign(), ast_var_name(), ast_var_value(), var, and ast_cdr::varshead.

Referenced by ast_cdr_dup().

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

void ast_cdr_detach ( struct ast_cdr cdr  ) 

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

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

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

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

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

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

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

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

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

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

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
cause the AST_CAUSE_* Returns nothing

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

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

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

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

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 173 of file cdr.c.

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

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

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

void ast_cdr_end ( struct ast_cdr cdr  ) 

End a call

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

Definition at line 888 of file cdr.c.

References ast_cdr::answer, AST_CDR_ANSWERED, AST_CDR_FAILED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_log(), ast_test_flag, ast_tvnow(), ast_tvzero(), 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_request_and_dial(), ast_bridge_call(), ast_cdr_fork(), ast_cdr_reset(), ast_hangup(), ast_pbx_outgoing_cdr_failed(), clear_caller(), and findmeexec().

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

int ast_cdr_engine_init ( void   ) 

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

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

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

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1525 of file cdr.c.

References do_reload().

01526 {
01527    return do_reload();
01528 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1520 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01521 {
01522    ast_cdr_submit_batch(batchsafeshutdown);
01523 }

void ast_cdr_failed ( struct ast_cdr cdr  ) 

Fail a call

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 728 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(), try_calling(), and wait_for_answer().

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

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

00930 {
00931    switch(flag) {
00932    case AST_CDR_OMIT:
00933       return "OMIT";
00934    case AST_CDR_BILLING:
00935       return "BILLING";
00936    case AST_CDR_DOCUMENTATION:
00937       return "DOCUMENTATION";
00938    }
00939    return "Unknown";
00940 }

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

Definition at line 434 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::next, ast_cdr_beitem::next, option_verbose, S_OR, ast_cdr::start, and VERBOSE_PREFIX_2.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

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

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

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

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

CDR channel variable retrieval

Definition at line 225 of file cdr.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_disp2str(), ast_cdr_flags2str(), ast_cdr_getvar_internal(), ast_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().

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

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

Definition at line 192 of file cdr.c.

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

Referenced by ast_cdr_getvar().

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

int ast_cdr_init ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

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

Definition at line 853 of file cdr.c.

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, ast_channel::amaflags, ast_cdr::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_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::name, ast_cdr::next, S_OR, set_one_cid(), ast_channel::uniqueid, and ast_cdr::uniqueid.

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

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

int ast_cdr_isset_unanswered ( void   ) 

Definition at line 165 of file cdr.c.

References unanswered.

Referenced by ring_entry(), and try_calling().

00166 {
00167    return unanswered;
00168 }

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 509 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.

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

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" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application.

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

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

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

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

Returns:
0 on success, -1 on failure

Definition at line 109 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::be, ast_cdr_beitem::desc, 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().

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 1066 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_cdr::next, and ast_cdr::start.

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

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

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

Definition at line 368 of file cdr.c.

References ast_build_string(), ast_cdr_getvar(), AST_LIST_TRAVERSE, ast_log(), ast_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().

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

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

Definition at line 942 of file cdr.c.

References ast_channel::accountcode, ast_cdr::accountcode, 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().

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

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

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

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

void ast_cdr_setanswer ( struct ast_cdr cdr,
struct timeval  t 
)

Set the answer time for a call

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

References ast_cdr::answer, 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().

00800 {
00801 
00802    for (; cdr; cdr = cdr->next) {
00803       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
00804          continue;
00805       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00806          continue;
00807       check_post(cdr);
00808       cdr->answer = t;
00809    }
00810 }

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

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

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

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

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

00845 {
00846    for (; cdr; cdr = cdr->next) {
00847       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00848          set_one_cid(cdr, c);
00849    }
00850    return 0;
00851 }

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 778 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(), ring_entry(), and try_calling().

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

void ast_cdr_setdisposition ( struct ast_cdr cdr,
long int  disposition 
)

Set the disposition for a call

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

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

Referenced by ast_bridge_call().

00813 {
00814 
00815    for (; cdr; cdr = cdr->next) {
00816       if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00817          continue;
00818       check_post(cdr);
00819       cdr->disposition = disposition;
00820    }
00821 }

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

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

00971 {
00972    struct ast_cdr *cdr = chan->cdr;
00973 
00974    for ( ; cdr ; cdr = cdr->next) {
00975       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 
00976          ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
00977    }
00978 
00979    return 0;
00980 }

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

Set a CDR channel variable

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

Definition at line 298 of file cdr.c.

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

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

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

void ast_cdr_specialized_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

Reset the detail record times, 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 1103 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, and ast_cdr::start.

Referenced by ast_bridge_call().

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

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

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

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

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

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

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

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

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

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

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

Definition at line 209 of file cdr.c.

References ast_localtime(), and t.

Referenced by ast_cdr_getvar().

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

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

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

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

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

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

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

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

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

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

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

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

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

static int do_reload ( void   )  [static]

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

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

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

Definition at line 1321 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, ast_cdr_batch::size, and unanswered.

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

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

Definition at line 1356 of file cdr.c.

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

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

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1153 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

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

static void post_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 1029 of file cdr.c.

References AST_CDR_ANSWERED, AST_CDR_FLAG_DIALED, 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().

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

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

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

01146 {
01147    batch->size = 0;
01148    batch->head = NULL;
01149    batch->tail = NULL;
01150 }

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

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

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

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

Definition at line 1217 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

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

static void submit_unscheduled_batch ( void   )  [static]

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

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


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

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

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

Referenced by ast_cdr_serialize_variables(), and ast_cdr_setvar().

int cdr_sched = -1 [static]

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 84 of file cdr.c.

Referenced by do_reload().

struct ast_cli_entry cli_status [static]

Definition at line 1374 of file cdr.c.

Referenced by ast_cdr_engine_init(), and dnsmgr_init().

struct ast_cli_entry cli_submit [static]

Definition at line 1367 of file cdr.c.

Referenced by do_reload().

int enabled [static]

struct sched_context* sched [static]

Definition at line 82 of file cdr.c.

int unanswered [static]

Is the CDR subsystem enabled ?

Definition at line 92 of file cdr.c.

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


Generated on Thu Oct 11 06:42:54 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6