Mon Mar 19 11:30:37 2012

Asterisk developer's documentation


cdr.c File Reference

Call Detail Record API. More...

#include "asterisk.h"
#include <signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/callerid.h"
#include "asterisk/manager.h"
#include "asterisk/causes.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 "asterisk/data.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

Functions

ast_cdrast_cdr_alloc (void)
 Allocate a CDR record.
int ast_cdr_amaflags2int (const char *flag)
 Convert a string to a detail record AMA flag.
void ast_cdr_answer (struct ast_cdr *cdr)
 Answer a call.
ast_cdrast_cdr_append (struct ast_cdr *cdr, struct ast_cdr *newcdr)
int ast_cdr_appenduserfield (struct ast_channel *chan, const char *userfield)
 Append to CDR user field for channel (stored in CDR).
void ast_cdr_busy (struct ast_cdr *cdr)
 Busy a call.
int ast_cdr_copy_vars (struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
int ast_cdr_data_add_structure (struct ast_data *tree, struct ast_cdr *cdr, int recur)
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.
void ast_cdr_discard (struct ast_cdr *cdr)
 Discard and free a CDR record.
char * ast_cdr_disp2str (int disposition)
 Disposition to a string.
int ast_cdr_disposition (struct ast_cdr *cdr, int cause)
 Save the result of the call based on the AST_CAUSE_*.
ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a record.
ast_cdrast_cdr_dup_unique (struct ast_cdr *cdr)
 Duplicate a record and increment the sequence number.
ast_cdrast_cdr_dup_unique_swap (struct ast_cdr *cdr)
 Duplicate a record and increment the sequence number of the old record.
void ast_cdr_end (struct ast_cdr *cdr)
 End a call.
int ast_cdr_engine_init (void)
 Load the configuration file cdr.conf and possibly start the CDR scheduling thread.
int ast_cdr_engine_reload (void)
 Reload the configuration file cdr.conf and start/stop CDR scheduling thread.
void ast_cdr_engine_term (void)
void ast_cdr_failed (struct ast_cdr *cdr)
 Fail a call.
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)
 Move the non-null data from the "from" cdr to the "to" cdr.
void ast_cdr_noanswer (struct ast_cdr *cdr)
 A call wasn't answered.
int ast_cdr_register (const char *name, const char *desc, ast_cdrbe be)
 Register a CDR handling engine.
void ast_cdr_reset (struct ast_cdr *cdr, struct ast_flags *_flags)
 Reset the detail record, optionally posting it first.
int ast_cdr_serialize_variables (struct ast_cdr *cdr, struct ast_str **buf, char delim, char sep, int recur)
int ast_cdr_setaccount (struct ast_channel *chan, const char *account)
 Set account code, will generate AMI event.
int ast_cdr_setamaflags (struct ast_channel *chan, const char *flag)
 Set AMA flags for channel.
void ast_cdr_setanswer (struct ast_cdr *cdr, struct timeval t)
 Set the answer time for a call.
void ast_cdr_setapp (struct ast_cdr *cdr, const char *app, const char *data)
 Set the last executed application.
int ast_cdr_setcid (struct ast_cdr *cdr, struct ast_channel *c)
 Initialize based on a channel.
void ast_cdr_setdestchan (struct ast_cdr *cdr, const char *chann)
 Set the destination channel, if there was one.
void ast_cdr_setdisposition (struct ast_cdr *cdr, long int disposition)
 Set the disposition for a call.
int ast_cdr_setpeeraccount (struct ast_channel *chan, const char *account)
 Set the peer account.
int ast_cdr_setuserfield (struct ast_channel *chan, const char *userfield)
 Set CDR user field for channel (stored in CDR).
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)
 Start a call.
void ast_cdr_submit_batch (int do_shutdown)
 Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines.
void ast_cdr_unregister (const char *name)
 Unregister a CDR handling engine.
int ast_cdr_update (struct ast_channel *c)
 Update CDR on a channel.
static void cdr_get_tv (struct timeval when, const char *fmt, char *buf, int bufsize)
static void cdr_merge_vars (struct ast_cdr *to, struct ast_cdr *from)
static int cdr_seq_inc (struct ast_cdr *cdr)
int check_cdr_enabled (void)
 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 (int reload)
static char * handle_cli_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_submit (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1
static const int BATCH_SCHEDULER_ONLY_DEFAULT = 0
static const int BATCH_SIZE_DEFAULT = 100
static const int BATCH_TIME_DEFAULT = 300
static int batchmode
static const int BATCHMODE_DEFAULT = 0
static int batchsafeshutdown
static int batchscheduleronly
static int batchsize
static int batchtime
static ast_mutex_t cdr_batch_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static ast_cond_t cdr_pending_cond
static ast_mutex_t cdr_pending_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static const char *const cdr_readonly_vars []
static int cdr_sched = -1
static int cdr_sequence = 0
static pthread_t cdr_thread = AST_PTHREADT_NULL
static struct ast_cli_entry cli_status = { .handler = handle_cli_status , .summary = "Display the CDR status" ,__VA_ARGS__ }
static struct ast_cli_entry cli_submit = { .handler = handle_cli_submit , .summary = "Posts all pending batched CDR data" ,__VA_ARGS__ }
static int enabled
static const int ENABLED_DEFAULT = 1
static struct sched_contextsched
static int unanswered
static const int UNANSWERED_DEFAULT = 0


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.


Function Documentation

struct ast_cdr* ast_cdr_alloc ( void   ) 

Allocate a CDR record.

Return values:
a malloc'd ast_cdr structure
NULL on error (malloc failure)

Definition at line 494 of file cdr.c.

References ast_calloc, ast_log(), and LOG_ERROR.

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

00495 {
00496    struct ast_cdr *x;
00497    x = ast_calloc(1, sizeof(*x));
00498    if (!x)
00499       ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
00500    return x;
00501 }

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

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

Referenced by ast_cdr_setamaflags(), build_device(), build_peer(), build_user(), config_parse_variables(), and set_config().

01098 {
01099    if (!strcasecmp(flag, "default"))
01100       return 0;
01101    if (!strcasecmp(flag, "omit"))
01102       return AST_CDR_OMIT;
01103    if (!strcasecmp(flag, "billing"))
01104       return AST_CDR_BILLING;
01105    if (!strcasecmp(flag, "documentation"))
01106       return AST_CDR_DOCUMENTATION;
01107    return -1;
01108 }

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
Note:
NULL argument is just fine.

Definition at line 729 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_bridge_call(), and ast_raw_answer().

00730 {
00731 
00732    for (; cdr; cdr = cdr->next) {
00733       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
00734          continue;
00735       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00736          continue;
00737       check_post(cdr);
00738       if (cdr->disposition < AST_CDR_ANSWERED)
00739          cdr->disposition = AST_CDR_ANSWERED;
00740       if (ast_tvzero(cdr->answer))
00741          cdr->answer = ast_tvnow();
00742    }
00743 }

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

Definition at line 1208 of file cdr.c.

References ast_cdr::next.

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

01209 {
01210    struct ast_cdr *ret;
01211 
01212    if (cdr) {
01213       ret = cdr;
01214 
01215       while (cdr->next)
01216          cdr = cdr->next;
01217       cdr->next = newcdr;
01218    } else {
01219       ret = newcdr;
01220    }
01221 
01222    return ret;
01223 }

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

Append to CDR user field for channel (stored in CDR).

Note:
The channel should be locked before calling.

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

01062 {
01063    struct ast_cdr *cdr = chan->cdr;
01064 
01065    for ( ; cdr ; cdr = cdr->next) {
01066       int len = strlen(cdr->userfield);
01067 
01068       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
01069          ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
01070    }
01071 
01072    return 0;
01073 }

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 745 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(), handle_cause(), pbx_builtin_busy(), and ring_entry().

00746 {
00747 
00748    for (; cdr; cdr = cdr->next) {
00749       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00750          check_post(cdr);
00751          cdr->disposition = AST_CDR_BUSY;
00752       }
00753    }
00754 }

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

00379 {
00380    struct ast_var_t *variables, *newvariable = NULL;
00381    struct varshead *headpa, *headpb;
00382    const char *var, *val;
00383    int x = 0;
00384 
00385    if (!to_cdr || !from_cdr) /* don't die if one of the pointers is null */
00386       return 0;
00387 
00388    headpa = &from_cdr->varshead;
00389    headpb = &to_cdr->varshead;
00390 
00391    AST_LIST_TRAVERSE(headpa,variables,entries) {
00392       if (variables &&
00393           (var = ast_var_name(variables)) && (val = ast_var_value(variables)) &&
00394           !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
00395          newvariable = ast_var_assign(var, val);
00396          AST_LIST_INSERT_HEAD(headpb, newvariable, entries);
00397          x++;
00398       }
00399    }
00400 
00401    return x;
00402 }

int ast_cdr_data_add_structure ( struct ast_data tree,
struct ast_cdr cdr,
int  recur 
)

Parameters:
[in] tree Where to insert the cdr.
[in] cdr The cdr structure to insert in 'tree'.
[in] recur Go throw all the cdr levels.
Return values:
<0 on error.
0 on success.

Definition at line 1640 of file cdr.c.

References ast_cdr_getvar(), ast_data_add_int(), ast_data_add_node(), ast_data_add_str(), AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_name(), ast_var_value(), cdr_readonly_vars, ast_var_t::entries, ast_cdr::next, var, and ast_cdr::varshead.

Referenced by ast_channel_data_add_structure().

01641 {
01642    struct ast_cdr *tmpcdr;
01643    struct ast_data *level;
01644    struct ast_var_t *variables;
01645    const char *var, *val;
01646    int x = 1, i;
01647    char workspace[256];
01648    char *tmp;
01649 
01650    if (!cdr) {
01651       return -1;
01652    }
01653 
01654    for (tmpcdr = cdr; tmpcdr; tmpcdr = (recur ? tmpcdr->next : NULL)) {
01655       level = ast_data_add_node(tree, "level");
01656       if (!level) {
01657          continue;
01658       }
01659 
01660       ast_data_add_int(level, "level_number", x);
01661 
01662       AST_LIST_TRAVERSE(&tmpcdr->varshead, variables, entries) {
01663          if (variables && (var = ast_var_name(variables)) &&
01664                (val = ast_var_value(variables)) && !ast_strlen_zero(var)
01665                && !ast_strlen_zero(val)) {
01666             ast_data_add_str(level, var, val);
01667          } else {
01668             break;
01669          }
01670       }
01671 
01672       for (i = 0; cdr_readonly_vars[i]; i++) {
01673          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 */
01674          ast_cdr_getvar(tmpcdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
01675          if (!tmp) {
01676             continue;
01677          }
01678          ast_data_add_str(level, cdr_readonly_vars[i], tmp);
01679       }
01680 
01681       x++;
01682    }
01683 
01684    return 0;
01685 }

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

References ast_calloc, AST_CDR_FLAG_POST_DISABLED, ast_cdr_free(), ast_debug, 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(), ast_cdr_batch_item::next, 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().

01314 {
01315    struct ast_cdr_batch_item *newtail;
01316    int curr;
01317 
01318    if (!cdr)
01319       return;
01320 
01321    /* maybe they disabled CDR stuff completely, so just drop it */
01322    if (!enabled) {
01323       ast_debug(1, "Dropping CDR !\n");
01324       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01325       ast_cdr_free(cdr);
01326       return;
01327    }
01328 
01329    /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
01330    if (!batchmode) {
01331       post_cdr(cdr);
01332       ast_cdr_free(cdr);
01333       return;
01334    }
01335 
01336    /* otherwise, each CDR gets put into a batch list (at the end) */
01337    ast_debug(1, "CDR detaching from this thread\n");
01338 
01339    /* we'll need a new tail for every CDR */
01340    if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
01341       post_cdr(cdr);
01342       ast_cdr_free(cdr);
01343       return;
01344    }
01345 
01346    /* don't traverse a whole list (just keep track of the tail) */
01347    ast_mutex_lock(&cdr_batch_lock);
01348    if (!batch)
01349       init_batch();
01350    if (!batch->head) {
01351       /* new batch is empty, so point the head at the new tail */
01352       batch->head = newtail;
01353    } else {
01354       /* already got a batch with something in it, so just append a new tail */
01355       batch->tail->next = newtail;
01356    }
01357    newtail->cdr = cdr;
01358    batch->tail = newtail;
01359    curr = batch->size++;
01360    ast_mutex_unlock(&cdr_batch_lock);
01361 
01362    /* if we have enough stuff to post, then do it */
01363    if (curr >= (batchsize - 1))
01364       submit_unscheduled_batch();
01365 }

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

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

Referenced by ast_async_goto(), ast_bridge_call(), ast_cdr_merge(), ast_channel_destructor(), and ast_dummy_channel_destructor().

00484 {
00485    while (cdr) {
00486       struct ast_cdr *next = cdr->next;
00487 
00488       ast_cdr_free_vars(cdr, 0);
00489       ast_free(cdr);
00490       cdr = next;
00491    }
00492 }

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

References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_FAILED, AST_CDR_NOANSWER, and AST_CDR_NULL.

Referenced by ast_cdr_getvar(), build_csv_record(), build_radius_record(), csv_log(), execute_cb(), manager_log(), and tds_log().

00952 {
00953    switch (disposition) {
00954    case AST_CDR_NULL:
00955       return "NO ANSWER"; /* by default, for backward compatibility */
00956    case AST_CDR_NOANSWER:
00957       return "NO ANSWER";
00958    case AST_CDR_FAILED:
00959       return "FAILED";
00960    case AST_CDR_BUSY:
00961       return "BUSY";
00962    case AST_CDR_ANSWERED:
00963       return "ANSWERED";
00964    }
00965    return "UNKNOWN";
00966 }

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

00783 {
00784    int res = 0;
00785 
00786    for (; cdr; cdr = cdr->next) {
00787       switch (cause) {  /* handle all the non failure, busy cases, return 0 not to set disposition,
00788                      return -1 to set disposition to FAILED */
00789       case AST_CAUSE_BUSY:
00790          ast_cdr_busy(cdr);
00791          break;
00792       case AST_CAUSE_NO_ANSWER:
00793          ast_cdr_noanswer(cdr);
00794          break;
00795       case AST_CAUSE_NORMAL:
00796          break;
00797       default:
00798          res = -1;
00799       }
00800    }
00801    return res;
00802 }

struct ast_cdr* ast_cdr_dup ( struct ast_cdr cdr  ) 

Duplicate a record.

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 207 of file cdr.c.

References ast_cdr_alloc(), and ast_cdr_copy_vars().

Referenced by ast_async_goto(), ast_cdr_dup_unique(), ast_cdr_dup_unique_swap(), ast_cdr_merge(), custom_log(), manager_log(), syslog_log(), and write_cdr().

00208 {
00209    struct ast_cdr *newcdr;
00210 
00211    if (!cdr) /* don't die if we get a null cdr pointer */
00212       return NULL;
00213    newcdr = ast_cdr_alloc();
00214    if (!newcdr)
00215       return NULL;
00216 
00217    memcpy(newcdr, cdr, sizeof(*newcdr));
00218    /* The varshead is unusable, volatile even, after the memcpy so we take care of that here */
00219    memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
00220    ast_cdr_copy_vars(newcdr, cdr);
00221    newcdr->next = NULL;
00222 
00223    return newcdr;
00224 }

struct ast_cdr* ast_cdr_dup_unique ( struct ast_cdr cdr  ) 

Duplicate a record and increment the sequence number.

Parameters:
cdr the record to duplicate
Return values:
a malloc'd ast_cdr structure,
NULL on error (malloc failure)
See also:
ast_cdr_dup()

ast_cdr_dup_unique_swap()

Definition at line 184 of file cdr.c.

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_cdr_fork().

00185 {
00186    struct ast_cdr *newcdr = ast_cdr_dup(cdr);
00187    if (!newcdr)
00188       return NULL;
00189 
00190    cdr_seq_inc(newcdr);
00191    return newcdr;
00192 }

struct ast_cdr* ast_cdr_dup_unique_swap ( struct ast_cdr cdr  ) 

Duplicate a record and increment the sequence number of the old record.

Parameters:
cdr the record to duplicate
Return values:
a malloc'd ast_cdr structure,
NULL on error (malloc failure)
Note:
This version increments the original CDR's sequence number rather than the duplicate's sequence number. The effect is as if the original CDR's sequence number was swapped with the duplicate's sequence number.
See also:
ast_cdr_dup()

ast_cdr_dup_unique()

Definition at line 194 of file cdr.c.

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_bridge_call(), and ast_cdr_reset().

00195 {
00196    struct ast_cdr *newcdr = ast_cdr_dup(cdr);
00197    if (!newcdr)
00198       return NULL;
00199 
00200    cdr_seq_inc(cdr);
00201    return newcdr;
00202 }

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

References AST_CDR_ANSWERED, AST_CDR_FAILED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_log(), AST_OPT_FLAG_INITIATED_SECONDS, ast_options, 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().

00926 {
00927    for ( ; cdr ; cdr = cdr->next) {
00928       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00929          continue;
00930       check_post(cdr);
00931       if (ast_tvzero(cdr->end))
00932          cdr->end = ast_tvnow();
00933       if (ast_tvzero(cdr->start)) {
00934          ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
00935          cdr->disposition = AST_CDR_FAILED;
00936       } else
00937          cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
00938       if (ast_tvzero(cdr->answer)) {
00939          if (cdr->disposition == AST_CDR_ANSWERED) {
00940             ast_log(LOG_WARNING, "CDR on channel '%s' has no answer time but is 'ANSWERED'\n", S_OR(cdr->channel, "<unknown>"));
00941             cdr->disposition = AST_CDR_FAILED;
00942          }
00943       } else {
00944          cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec;
00945          if (ast_test_flag(&ast_options, AST_OPT_FLAG_INITIATED_SECONDS))
00946             cdr->billsec += cdr->end.tv_usec > cdr->answer.tv_usec ? 1 : 0;
00947       }
00948    }
00949 }

int ast_cdr_engine_init ( void   ) 

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

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

01607 {
01608    int res;
01609 
01610    sched = sched_context_create();
01611    if (!sched) {
01612       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
01613       return -1;
01614    }
01615 
01616    ast_cli_register(&cli_status);
01617 
01618    res = do_reload(0);
01619    if (res) {
01620       ast_mutex_lock(&cdr_batch_lock);
01621       res = init_batch();
01622       ast_mutex_unlock(&cdr_batch_lock);
01623    }
01624 
01625    return res;
01626 }

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1635 of file cdr.c.

References do_reload().

01636 {
01637    return do_reload(1);
01638 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1630 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by can_safely_quit(), and do_reload().

01631 {
01632    ast_cdr_submit_batch(batchsafeshutdown);
01633 }

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

References AST_CDR_FAILED, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), 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(), handle_cause(), and wait_for_answer().

00757 {
00758    for (; cdr; cdr = cdr->next) {
00759       check_post(cdr);
00760       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00761          check_post(cdr);
00762          if (cdr->disposition < AST_CDR_FAILED)
00763             cdr->disposition = AST_CDR_FAILED;
00764       }
00765    }
00766 }

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

Definition at line 969 of file cdr.c.

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

Referenced by _sip_show_peer(), _skinny_show_line(), ast_cdr_getvar(), ast_channel_data_add_structure(), build_csv_record(), build_radius_record(), csv_log(), manager_log(), peers_data_provider_get(), sip_show_user(), tds_log(), and users_data_provider_get().

00970 {
00971    switch (flag) {
00972    case AST_CDR_OMIT:
00973       return "OMIT";
00974    case AST_CDR_BILLING:
00975       return "BILLING";
00976    case AST_CDR_DOCUMENTATION:
00977       return "DOCUMENTATION";
00978    }
00979    return "Unknown";
00980 }

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

Definition at line 470 of file cdr.c.

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

Referenced by ast_cdr_detach(), and do_batch_backend_process().

00471 {
00472 
00473    while (cdr) {
00474       struct ast_cdr *next = cdr->next;
00475 
00476       ast_cdr_free_vars(cdr, 0);
00477       ast_free(cdr);
00478       cdr = next;
00479    }
00480 }

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

00450 {
00451 
00452    /* clear variables */
00453    for (; cdr; cdr = recur ? cdr->next : NULL) {
00454       struct ast_var_t *vardata;
00455       struct varshead *headp = &cdr->varshead;
00456       while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
00457          ast_var_delete(vardata);
00458    }
00459 }

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 258 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_tvdiff_ms(), ast_tvnow(), 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::linkedid, ast_cdr::peeraccount, ast_cdr::sequence, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by ast_cdr_data_add_structure(), ast_cdr_serialize_variables(), cdr_handler(), cdr_read(), odbc_log(), and pgsql_log().

00259 {
00260    const char *fmt = "%Y-%m-%d %T";
00261    const char *varbuf;
00262 
00263    if (!cdr)  /* don't die if the cdr is null */
00264       return;
00265 
00266    *ret = NULL;
00267    /* special vars (the ones from the struct ast_cdr when requested by name)
00268       I'd almost say we should convert all the stringed vals to vars */
00269 
00270    if (!strcasecmp(name, "clid"))
00271       ast_copy_string(workspace, cdr->clid, workspacelen);
00272    else if (!strcasecmp(name, "src"))
00273       ast_copy_string(workspace, cdr->src, workspacelen);
00274    else if (!strcasecmp(name, "dst"))
00275       ast_copy_string(workspace, cdr->dst, workspacelen);
00276    else if (!strcasecmp(name, "dcontext"))
00277       ast_copy_string(workspace, cdr->dcontext, workspacelen);
00278    else if (!strcasecmp(name, "channel"))
00279       ast_copy_string(workspace, cdr->channel, workspacelen);
00280    else if (!strcasecmp(name, "dstchannel"))
00281       ast_copy_string(workspace, cdr->dstchannel, workspacelen);
00282    else if (!strcasecmp(name, "lastapp"))
00283       ast_copy_string(workspace, cdr->lastapp, workspacelen);
00284    else if (!strcasecmp(name, "lastdata"))
00285       ast_copy_string(workspace, cdr->lastdata, workspacelen);
00286    else if (!strcasecmp(name, "start"))
00287       cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
00288    else if (!strcasecmp(name, "answer"))
00289       cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
00290    else if (!strcasecmp(name, "end"))
00291       cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
00292    else if (!strcasecmp(name, "duration"))
00293       snprintf(workspace, workspacelen, "%ld", cdr->duration ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
00294    else if (!strcasecmp(name, "billsec"))
00295       snprintf(workspace, workspacelen, "%ld", cdr->billsec || cdr->answer.tv_sec == 0 ? cdr->billsec : (long)ast_tvdiff_ms(ast_tvnow(), cdr->answer) / 1000);
00296    else if (!strcasecmp(name, "disposition")) {
00297       if (raw) {
00298          snprintf(workspace, workspacelen, "%ld", cdr->disposition);
00299       } else {
00300          ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
00301       }
00302    } else if (!strcasecmp(name, "amaflags")) {
00303       if (raw) {
00304          snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
00305       } else {
00306          ast_copy_string(workspace, ast_cdr_flags2str(cdr->amaflags), workspacelen);
00307       }
00308    } else if (!strcasecmp(name, "accountcode"))
00309       ast_copy_string(workspace, cdr->accountcode, workspacelen);
00310    else if (!strcasecmp(name, "peeraccount"))
00311       ast_copy_string(workspace, cdr->peeraccount, workspacelen);
00312    else if (!strcasecmp(name, "uniqueid"))
00313       ast_copy_string(workspace, cdr->uniqueid, workspacelen);
00314    else if (!strcasecmp(name, "linkedid"))
00315       ast_copy_string(workspace, cdr->linkedid, workspacelen);
00316    else if (!strcasecmp(name, "userfield"))
00317       ast_copy_string(workspace, cdr->userfield, workspacelen);
00318    else if (!strcasecmp(name, "sequence"))
00319       snprintf(workspace, workspacelen, "%d", cdr->sequence);
00320    else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
00321       ast_copy_string(workspace, varbuf, workspacelen);
00322    else
00323       workspace[0] = '\0';
00324 
00325    if (!ast_strlen_zero(workspace))
00326       *ret = workspace;
00327 }

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

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

00227 {
00228    if (ast_strlen_zero(name))
00229       return NULL;
00230 
00231    for (; cdr; cdr = recur ? cdr->next : NULL) {
00232       struct ast_var_t *variables;
00233       struct varshead *headp = &cdr->varshead;
00234       AST_LIST_TRAVERSE(headp, variables, entries) {
00235          if (!strcasecmp(name, ast_var_name(variables)))
00236             return ast_var_value(variables);
00237       }
00238    }
00239 
00240    return NULL;
00241 }

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
Note:
The channel should be locked before calling.
Returns:
0 by default

Definition at line 889 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, cdr_seq_inc(), ast_cdr::channel, ast_channel::context, ast_channel::exten, ast_channel::linkedid, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::name, ast_cdr::next, ast_channel::peeraccount, S_OR, set_one_cid(), and ast_channel::uniqueid.

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

00890 {
00891    for ( ; cdr ; cdr = cdr->next) {
00892       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00893          ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
00894          set_one_cid(cdr, c);
00895          cdr_seq_inc(cdr);
00896 
00897          cdr->disposition = (c->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
00898          cdr->amaflags = c->amaflags ? c->amaflags :  ast_default_amaflags;
00899          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00900          ast_copy_string(cdr->peeraccount, c->peeraccount, sizeof(cdr->peeraccount));
00901          /* Destination information */
00902          ast_copy_string(cdr->dst, S_OR(c->macroexten,c->exten), sizeof(cdr->dst));
00903          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext,c->context), sizeof(cdr->dcontext));
00904          /* Unique call identifier */
00905          ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid));
00906          /* Linked call identifier */
00907          ast_copy_string(cdr->linkedid, c->linkedid, sizeof(cdr->linkedid));
00908       }
00909    }
00910    return 0;
00911 }

int ast_cdr_isset_unanswered ( void   ) 

Definition at line 179 of file cdr.c.

References unanswered.

Referenced by ring_entry().

00180 {
00181    return unanswered;
00182 }

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 538 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::peeraccount, ast_cdr::src, ast_cdr::start, and ast_cdr::userfield.

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

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

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

Referenced by ast_cdr_disposition(), and handle_cause().

00769 {
00770    while (cdr) {
00771       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00772          check_post(cdr);
00773          cdr->disposition = AST_CDR_NOANSWER;
00774       }
00775       cdr = cdr->next;
00776    }
00777 }

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

Register a CDR handling engine.

Return values:
0 on success.
-1 on error

Definition at line 124 of file cdr.c.

References ast_calloc, ast_copy_string(), ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_cdr_beitem::list, LOG_WARNING, and ast_cdr_beitem::name.

Referenced by config_module(), load_config(), load_module(), odbc_load_module(), and unload_module().

00125 {
00126    struct ast_cdr_beitem *i = NULL;
00127 
00128    if (!name)
00129       return -1;
00130 
00131    if (!be) {
00132       ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
00133       return -1;
00134    }
00135 
00136    AST_RWLIST_WRLOCK(&be_list);
00137    AST_RWLIST_TRAVERSE(&be_list, i, list) {
00138       if (!strcasecmp(name, i->name)) {
00139          ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
00140          AST_RWLIST_UNLOCK(&be_list);
00141          return -1;
00142       }
00143    }
00144 
00145    if (!(i = ast_calloc(1, sizeof(*i))))
00146       return -1;
00147 
00148    i->be = be;
00149    ast_copy_string(i->name, name, sizeof(i->name));
00150    ast_copy_string(i->desc, desc, sizeof(i->desc));
00151 
00152    AST_RWLIST_INSERT_HEAD(&be_list, i, list);
00153    AST_RWLIST_UNLOCK(&be_list);
00154 
00155    return 0;
00156 }

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

References ast_cdr::answer, ast_cdr_detach(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POST_ENABLE, 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(), dial_exec_full(), and pbx_builtin_resetcdr().

01142 {
01143    struct ast_cdr *duplicate;
01144    struct ast_flags flags = { 0 };
01145 
01146    if (_flags)
01147       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
01148 
01149    for ( ; cdr ; cdr = cdr->next) {
01150       /* Detach if post is requested */
01151       if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01152          if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
01153             ast_cdr_end(cdr);
01154             if ((duplicate = ast_cdr_dup_unique_swap(cdr))) {
01155                ast_cdr_detach(duplicate);
01156             }
01157             ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
01158          }
01159 
01160          /* enable CDR only */
01161          if (ast_test_flag(&flags, AST_CDR_FLAG_POST_ENABLE)) {
01162             ast_clear_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01163             continue;
01164          }
01165 
01166          /* clear variables */
01167          if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
01168             ast_cdr_free_vars(cdr, 0);
01169          }
01170 
01171          /* Reset to initial state */
01172          ast_clear_flag(cdr, AST_FLAGS_ALL);
01173          memset(&cdr->start, 0, sizeof(cdr->start));
01174          memset(&cdr->end, 0, sizeof(cdr->end));
01175          memset(&cdr->answer, 0, sizeof(cdr->answer));
01176          cdr->billsec = 0;
01177          cdr->duration = 0;
01178          ast_cdr_start(cdr);
01179          cdr->disposition = AST_CDR_NOANSWER;
01180       }
01181    }
01182 }

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

Definition at line 404 of file cdr.c.

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

00405 {
00406    struct ast_var_t *variables;
00407    const char *var;
00408    char *tmp;
00409    char workspace[256];
00410    int total = 0, x = 0, i;
00411 
00412    ast_str_reset(*buf);
00413 
00414    for (; cdr; cdr = recur ? cdr->next : NULL) {
00415       if (++x > 1)
00416          ast_str_append(buf, 0, "\n");
00417 
00418       AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
00419          if (!(var = ast_var_name(variables))) {
00420             continue;
00421          }
00422 
00423          if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variables), ""), sep) < 0) {
00424             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
00425             break;
00426          }
00427 
00428          total++;
00429       }
00430 
00431       for (i = 0; cdr_readonly_vars[i]; i++) {
00432          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 */
00433          ast_cdr_getvar(cdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
00434          if (!tmp)
00435             continue;
00436 
00437          if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, tmp, sep) < 0) {
00438             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
00439             break;
00440          } else
00441             total++;
00442       }
00443    }
00444 
00445    return total;
00446 }

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

Set account code, will generate AMI event.

Note:
The channel should be locked before calling.

Definition at line 982 of file cdr.c.

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

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

00983 {
00984    struct ast_cdr *cdr = chan->cdr;
00985    const char *old_acct = "";
00986 
00987    if (!ast_strlen_zero(chan->accountcode)) {
00988       old_acct = ast_strdupa(chan->accountcode);
00989    }
00990 
00991    ast_string_field_set(chan, accountcode, account);
00992    for ( ; cdr ; cdr = cdr->next) {
00993       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00994          ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode));
00995       }
00996    }
00997 
00998    ast_manager_event(chan, EVENT_FLAG_CALL, "NewAccountCode",
00999          "Channel: %s\r\n"
01000          "Uniqueid: %s\r\n"
01001          "AccountCode: %s\r\n"
01002          "OldAccountCode: %s\r\n",
01003          chan->name, chan->uniqueid, chan->accountcode, old_acct);
01004 
01005    return 0;
01006 }

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

Set AMA flags for channel.

Note:
The channel should be locked before calling.

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

01035 {
01036    struct ast_cdr *cdr;
01037    int newflag = ast_cdr_amaflags2int(flag);
01038    if (newflag) {
01039       for (cdr = chan->cdr; cdr; cdr = cdr->next) {
01040          if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01041             cdr->amaflags = newflag;
01042          }
01043       }
01044    }
01045 
01046    return 0;
01047 }

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

00827 {
00828 
00829    for (; cdr; cdr = cdr->next) {
00830       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
00831          continue;
00832       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00833          continue;
00834       check_post(cdr);
00835       cdr->answer = t;
00836    }
00837 }

void ast_cdr_setapp ( struct ast_cdr cdr,
const char *  app,
const 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 814 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().

00815 {
00816 
00817    for (; cdr; cdr = cdr->next) {
00818       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00819          check_post(cdr);
00820          ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp));
00821          ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata));
00822       }
00823    }
00824 }

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
Note:
The channel should be locked before calling.
Returns:
0 by default

Definition at line 875 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_channel_set_caller_event(), ast_set_callerid(), and callerid_write().

00876 {
00877    for (; cdr; cdr = cdr->next) {
00878       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00879          set_one_cid(cdr, c);
00880    }
00881    return 0;
00882 }

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

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

Referenced by dial_exec_full(), parked_call_exec(), and ring_entry().

00805 {
00806    for (; cdr; cdr = cdr->next) {
00807       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00808          check_post(cdr);
00809          ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
00810       }
00811    }
00812 }

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

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

Referenced by ast_bridge_call().

00840 {
00841 
00842    for (; cdr; cdr = cdr->next) {
00843       if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00844          continue;
00845       check_post(cdr);
00846       cdr->disposition = disposition;
00847    }
00848 }

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

Set the peer account.

Note:
The channel should be locked before calling.

Definition at line 1008 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_manager_event, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, EVENT_FLAG_CALL, ast_cdr::next, ast_cdr::peeraccount, and ast_channel::peeraccount.

Referenced by cdr_write().

01009 {
01010    struct ast_cdr *cdr = chan->cdr;
01011    const char *old_acct = "";
01012 
01013    if (!ast_strlen_zero(chan->peeraccount)) {
01014       old_acct = ast_strdupa(chan->peeraccount);
01015    }
01016 
01017    ast_string_field_set(chan, peeraccount, account);
01018    for ( ; cdr ; cdr = cdr->next) {
01019       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01020          ast_copy_string(cdr->peeraccount, chan->peeraccount, sizeof(cdr->peeraccount));
01021       }
01022    }
01023 
01024    ast_manager_event(chan, EVENT_FLAG_CALL, "NewPeerAccount",
01025          "Channel: %s\r\n"
01026          "Uniqueid: %s\r\n"
01027          "PeerAccount: %s\r\n"
01028          "OldPeerAccount: %s\r\n",
01029          chan->name, chan->uniqueid, chan->peeraccount, old_acct);
01030 
01031    return 0;
01032 }

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

Set CDR user field for channel (stored in CDR).

Note:
The channel should be locked before calling.

Definition at line 1049 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(), ast_bridge_call(), cdr_write(), handle_request_info(), and start_monitor_exec().

01050 {
01051    struct ast_cdr *cdr = chan->cdr;
01052 
01053    for ( ; cdr ; cdr = cdr->next) {
01054       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
01055          ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
01056    }
01057 
01058    return 0;
01059 }

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

00338 {
00339    struct ast_var_t *newvariable;
00340    struct varshead *headp;
00341    int x;
00342 
00343    for (x = 0; cdr_readonly_vars[x]; x++) {
00344       if (!strcasecmp(name, cdr_readonly_vars[x])) {
00345          ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!.\n", name);
00346          return -1;
00347       }
00348    }
00349 
00350    if (!cdr) {
00351       ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n");
00352       return -1;
00353    }
00354 
00355    for (; cdr; cdr = recur ? cdr->next : NULL) {
00356       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00357          continue;
00358       headp = &cdr->varshead;
00359       AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
00360          if (!strcasecmp(ast_var_name(newvariable), name)) {
00361             /* there is already such a variable, delete it */
00362             AST_LIST_REMOVE_CURRENT(entries);
00363             ast_var_delete(newvariable);
00364             break;
00365          }
00366       }
00367       AST_LIST_TRAVERSE_SAFE_END;
00368 
00369       if (value) {
00370          newvariable = ast_var_assign(name, value);
00371          AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00372       }
00373    }
00374 
00375    return 0;
00376 }

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

01185 {
01186    struct ast_flags flags = { 0 };
01187 
01188    if (_flags)
01189       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
01190 
01191    /* Reset to initial state */
01192    if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) { /* But do NOT lose the NoCDR() setting */
01193       ast_clear_flag(cdr, AST_FLAGS_ALL);
01194       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01195    } else {
01196       ast_clear_flag(cdr, AST_FLAGS_ALL);
01197    }
01198 
01199    memset(&cdr->start, 0, sizeof(cdr->start));
01200    memset(&cdr->end, 0, sizeof(cdr->end));
01201    memset(&cdr->answer, 0, sizeof(cdr->answer));
01202    cdr->billsec = 0;
01203    cdr->duration = 0;
01204    ast_cdr_start(cdr);
01205    cdr->disposition = AST_CDR_NULL;
01206 }

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

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

Referenced by __ast_channel_alloc_ap(), __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().

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

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

References ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, AST_PTHREADT_NULL, batch, batchscheduleronly, cdr_batch_lock, do_batch_backend_process(), ast_cdr_batch::head, LOG_WARNING, and reset_batch().

Referenced by ast_cdr_engine_term(), and submit_scheduled_batch().

01263 {
01264    struct ast_cdr_batch_item *oldbatchitems = NULL;
01265    pthread_t batch_post_thread = AST_PTHREADT_NULL;
01266 
01267    /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
01268    if (!batch || !batch->head)
01269       return;
01270 
01271    /* move the old CDRs aside, and prepare a new CDR batch */
01272    ast_mutex_lock(&cdr_batch_lock);
01273    oldbatchitems = batch->head;
01274    reset_batch();
01275    ast_mutex_unlock(&cdr_batch_lock);
01276 
01277    /* if configured, spawn a new thread to post these CDRs,
01278       also try to save as much as possible if we are shutting down safely */
01279    if (batchscheduleronly || do_shutdown) {
01280       ast_debug(1, "CDR single-threaded batch processing begins now\n");
01281       do_batch_backend_process(oldbatchitems);
01282    } else {
01283       if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
01284          ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
01285          do_batch_backend_process(oldbatchitems);
01286       } else {
01287          ast_debug(1, "CDR multi-threaded batch processing begins now\n");
01288       }
01289    }
01290 }

void ast_cdr_unregister ( const char *  name  ) 

Unregister a CDR handling engine.

unregister a CDR driver

Definition at line 159 of file cdr.c.

References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_cdr_beitem::list, and ast_cdr_beitem::name.

Referenced by load_config(), odbc_load_module(), reload(), tds_unload_module(), and unload_module().

00160 {
00161    struct ast_cdr_beitem *i = NULL;
00162 
00163    AST_RWLIST_WRLOCK(&be_list);
00164    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
00165       if (!strcasecmp(name, i->name)) {
00166          AST_RWLIST_REMOVE_CURRENT(list);
00167          break;
00168       }
00169    }
00170    AST_RWLIST_TRAVERSE_SAFE_END;
00171    AST_RWLIST_UNLOCK(&be_list);
00172 
00173    if (i) {
00174       ast_verb(2, "Unregistered '%s' CDR backend\n", name);
00175       ast_free(i);
00176    }
00177 }

int ast_cdr_update ( struct ast_channel chan  ) 

Update CDR on a channel.

Note:
The channel should be locked before calling.

Definition at line 1075 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::linkedid, ast_channel::macrocontext, ast_channel::macroexten, ast_cdr::next, ast_channel::peeraccount, 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().

01076 {
01077    struct ast_cdr *cdr = c->cdr;
01078 
01079    for ( ; cdr ; cdr = cdr->next) {
01080       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01081          set_one_cid(cdr, c);
01082 
01083          /* Copy account code et-al */
01084          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
01085          ast_copy_string(cdr->peeraccount, c->peeraccount, sizeof(cdr->peeraccount));
01086          ast_copy_string(cdr->linkedid, c->linkedid, sizeof(cdr->linkedid));
01087 
01088          /* Destination information */ /* XXX privilege macro* ? */
01089          ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst));
01090          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext));
01091       }
01092    }
01093 
01094    return 0;
01095 }

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

Definition at line 243 of file cdr.c.

References ast_localtime(), and ast_strftime().

Referenced by ast_cdr_getvar().

00244 {
00245    if (fmt == NULL) {   /* raw mode */
00246       snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
00247    } else {
00248       if (when.tv_sec) {
00249          struct ast_tm tm;
00250 
00251          ast_localtime(&when, &tm, NULL);
00252          ast_strftime(buf, bufsize, fmt, &tm);
00253       }
00254    }
00255 }

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

Definition at line 503 of file cdr.c.

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

00504 {
00505    struct ast_var_t *variablesfrom,*variablesto;
00506    struct varshead *headpfrom = &to->varshead;
00507    struct varshead *headpto = &from->varshead;
00508    AST_LIST_TRAVERSE_SAFE_BEGIN(headpfrom, variablesfrom, entries) {
00509       /* for every var in from, stick it in to */
00510       const char *fromvarname, *fromvarval;
00511       const char *tovarname = NULL, *tovarval = NULL;
00512       fromvarname = ast_var_name(variablesfrom);
00513       fromvarval = ast_var_value(variablesfrom);
00514       tovarname = 0;
00515 
00516       /* now, quick see if that var is in the 'to' cdr already */
00517       AST_LIST_TRAVERSE(headpto, variablesto, entries) {
00518 
00519          /* now, quick see if that var is in the 'to' cdr already */
00520          if ( strcasecmp(fromvarname, ast_var_name(variablesto)) == 0 ) {
00521             tovarname = ast_var_name(variablesto);
00522             tovarval = ast_var_value(variablesto);
00523             break;
00524          }
00525       }
00526       if (tovarname && strcasecmp(fromvarval,tovarval) != 0) {  /* this message here to see how irritating the userbase finds it */
00527          ast_log(LOG_NOTICE, "Merging CDR's: variable %s value %s dropped in favor of value %s\n", tovarname, fromvarval, tovarval);
00528          continue;
00529       } else if (tovarname && strcasecmp(fromvarval,tovarval) == 0) /* if they are the same, the job is done */
00530          continue;
00531 
00532       /* rip this var out of the from cdr, and stick it in the to cdr */
00533       AST_LIST_MOVE_CURRENT(headpto, entries);
00534    }
00535    AST_LIST_TRAVERSE_SAFE_END;
00536 }

static int cdr_seq_inc ( struct ast_cdr cdr  )  [static]

Definition at line 884 of file cdr.c.

References ast_atomic_fetchadd_int(), cdr_sequence, and ast_cdr::sequence.

Referenced by ast_cdr_dup_unique(), ast_cdr_dup_unique_swap(), and ast_cdr_init().

00885 {
00886    return (cdr->sequence = ast_atomic_fetchadd_int(&cdr_sequence, +1));
00887 }

int check_cdr_enabled ( void   ) 

Return TRUE if CDR subsystem is enabled.

Definition at line 114 of file cdr.c.

References enabled.

Referenced by action_coresettings(), and handle_show_settings().

00115 {
00116    return enabled;
00117 }

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

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

00463 {
00464    if (!cdr)
00465       return;
00466    if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
00467       ast_log(LOG_NOTICE, "CDR on channel '%s' already posted\n", S_OR(cdr->channel, "<unknown>"));
00468 }

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

Definition at line 1245 of file cdr.c.

References ast_cdr_free(), ast_free, ast_cdr_batch_item::cdr, ast_cdr_batch_item::next, and post_cdr().

Referenced by ast_cdr_submit_batch().

01246 {
01247    struct ast_cdr_batch_item *processeditem;
01248    struct ast_cdr_batch_item *batchitem = data;
01249 
01250    /* Push each CDR into storage mechanism(s) and free all the memory */
01251    while (batchitem) {
01252       post_cdr(batchitem->cdr);
01253       ast_cdr_free(batchitem->cdr);
01254       processeditem = batchitem;
01255       batchitem = batchitem->next;
01256       ast_free(processeditem);
01257    }
01258 
01259    return NULL;
01260 }

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

Definition at line 1367 of file cdr.c.

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

Referenced by do_reload().

01368 {
01369    struct timespec timeout;
01370    int schedms;
01371    int numevents = 0;
01372 
01373    for (;;) {
01374       struct timeval now;
01375       schedms = ast_sched_wait(sched);
01376       /* this shouldn't happen, but provide a 1 second default just in case */
01377       if (schedms <= 0)
01378          schedms = 1000;
01379       now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
01380       timeout.tv_sec = now.tv_sec;
01381       timeout.tv_nsec = now.tv_usec * 1000;
01382       /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
01383       ast_mutex_lock(&cdr_pending_lock);
01384       ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
01385       numevents = ast_sched_runq(sched);
01386       ast_mutex_unlock(&cdr_pending_lock);
01387       ast_debug(2, "Processed %d scheduled CDR batches from the run queue\n", numevents);
01388    }
01389 
01390    return NULL;
01391 }

static int do_reload ( int  reload  )  [static]

Definition at line 1475 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_load2(), ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN, AST_OPT_FLAG_INITIATED_SECONDS, 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, BATCHMODE_DEFAULT, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_batch_lock, cdr_pending_cond, cdr_sched, cdr_thread, cli_submit, config, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, do_cdr(), enabled, ENABLED_DEFAULT, EVENT_FLAG_SYSTEM, LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_event, submit_scheduled_batch(), unanswered, and UNANSWERED_DEFAULT.

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

01476 {
01477    struct ast_config *config;
01478    const char *enabled_value;
01479    const char *unanswered_value;
01480    const char *batched_value;
01481    const char *scheduleronly_value;
01482    const char *batchsafeshutdown_value;
01483    const char *size_value;
01484    const char *time_value;
01485    const char *end_before_h_value;
01486    const char *initiatedseconds_value;
01487    int cfg_size;
01488    int cfg_time;
01489    int was_enabled;
01490    int was_batchmode;
01491    int res=0;
01492    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01493 
01494    if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
01495       return 0;
01496    }
01497 
01498    ast_mutex_lock(&cdr_batch_lock);
01499 
01500    was_enabled = enabled;
01501    was_batchmode = batchmode;
01502 
01503    batchsize = BATCH_SIZE_DEFAULT;
01504    batchtime = BATCH_TIME_DEFAULT;
01505    batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
01506    batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
01507    enabled = ENABLED_DEFAULT;
01508    batchmode = BATCHMODE_DEFAULT;
01509    unanswered = UNANSWERED_DEFAULT;
01510 
01511    if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
01512       ast_mutex_unlock(&cdr_batch_lock);
01513       return 0;
01514    }
01515 
01516    /* don't run the next scheduled CDR posting while reloading */
01517    AST_SCHED_DEL(sched, cdr_sched);
01518 
01519    if (config) {
01520       if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
01521          enabled = ast_true(enabled_value);
01522       }
01523       if ((unanswered_value = ast_variable_retrieve(config, "general", "unanswered"))) {
01524          unanswered = ast_true(unanswered_value);
01525       }
01526       if ((batched_value = ast_variable_retrieve(config, "general", "batch"))) {
01527          batchmode = ast_true(batched_value);
01528       }
01529       if ((scheduleronly_value = ast_variable_retrieve(config, "general", "scheduleronly"))) {
01530          batchscheduleronly = ast_true(scheduleronly_value);
01531       }
01532       if ((batchsafeshutdown_value = ast_variable_retrieve(config, "general", "safeshutdown"))) {
01533          batchsafeshutdown = ast_true(batchsafeshutdown_value);
01534       }
01535       if ((size_value = ast_variable_retrieve(config, "general", "size"))) {
01536          if (sscanf(size_value, "%30d", &cfg_size) < 1)
01537             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", size_value);
01538          else if (cfg_size < 0)
01539             ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
01540          else
01541             batchsize = cfg_size;
01542       }
01543       if ((time_value = ast_variable_retrieve(config, "general", "time"))) {
01544          if (sscanf(time_value, "%30d", &cfg_time) < 1)
01545             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", time_value);
01546          else if (cfg_time < 0)
01547             ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
01548          else
01549             batchtime = cfg_time;
01550       }
01551       if ((end_before_h_value = ast_variable_retrieve(config, "general", "endbeforehexten")))
01552          ast_set2_flag(&ast_options, ast_true(end_before_h_value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
01553       if ((initiatedseconds_value = ast_variable_retrieve(config, "general", "initiatedseconds")))
01554          ast_set2_flag(&ast_options, ast_true(initiatedseconds_value), AST_OPT_FLAG_INITIATED_SECONDS);
01555    }
01556 
01557    if (enabled && !batchmode) {
01558       ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
01559    } else if (enabled && batchmode) {
01560       cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01561       ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
01562    } else {
01563       ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
01564    }
01565 
01566    /* if this reload enabled the CDR batch mode, create the background thread
01567       if it does not exist */
01568    if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
01569       ast_cond_init(&cdr_pending_cond, NULL);
01570       if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
01571          ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
01572          AST_SCHED_DEL(sched, cdr_sched);
01573       } else {
01574          ast_cli_register(&cli_submit);
01575          ast_register_atexit(ast_cdr_engine_term);
01576          res = 0;
01577       }
01578    /* if this reload disabled the CDR and/or batch mode and there is a background thread,
01579       kill it */
01580    } else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
01581       /* wake up the thread so it will exit */
01582       pthread_cancel(cdr_thread);
01583       pthread_kill(cdr_thread, SIGURG);
01584       pthread_join(cdr_thread, NULL);
01585       cdr_thread = AST_PTHREADT_NULL;
01586       ast_cond_destroy(&cdr_pending_cond);
01587       ast_cli_unregister(&cli_submit);
01588       ast_unregister_atexit(ast_cdr_engine_term);
01589       res = 0;
01590       /* if leaving batch mode, then post the CDRs in the batch,
01591          and don't reschedule, since we are stopping CDR logging */
01592       if (!batchmode && was_batchmode) {
01593          ast_cdr_engine_term();
01594       }
01595    } else {
01596       res = 0;
01597    }
01598 
01599    ast_mutex_unlock(&cdr_batch_lock);
01600    ast_config_destroy(config);
01601    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: CDR\r\nMessage: CDR subsystem reload requested\r\n");
01602 
01603    return res;
01604 }

static char* handle_cli_status ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1393 of file cdr.c.

References ast_cli_args::argc, ast_cli(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_sched_when(), batch, batchmode, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_sched, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, enabled, ESS, ast_cli_args::fd, ast_cdr_beitem::list, ast_cdr_beitem::name, ast_cdr_batch::size, unanswered, and ast_cli_entry::usage.

01394 {
01395    struct ast_cdr_beitem *beitem=NULL;
01396    int cnt=0;
01397    long nextbatchtime=0;
01398 
01399    switch (cmd) {
01400    case CLI_INIT:
01401       e->command = "cdr show status";
01402       e->usage =
01403          "Usage: cdr show status\n"
01404          "  Displays the Call Detail Record engine system status.\n";
01405       return NULL;
01406    case CLI_GENERATE:
01407       return NULL;
01408    }
01409 
01410    if (a->argc > 3)
01411       return CLI_SHOWUSAGE;
01412 
01413    ast_cli(a->fd, "\n");
01414    ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
01415    ast_cli(a->fd, "----------------------------------\n");
01416    ast_cli(a->fd, "  Logging:                    %s\n", enabled ? "Enabled" : "Disabled");
01417    ast_cli(a->fd, "  Mode:                       %s\n", batchmode ? "Batch" : "Simple");
01418    if (enabled) {
01419       ast_cli(a->fd, "  Log unanswered calls:       %s\n\n", unanswered ? "Yes" : "No");
01420       if (batchmode) {
01421          ast_cli(a->fd, "* Batch Mode Settings\n");
01422          ast_cli(a->fd, "  -------------------\n");
01423          if (batch)
01424             cnt = batch->size;
01425          if (cdr_sched > -1)
01426             nextbatchtime = ast_sched_when(sched, cdr_sched);
01427          ast_cli(a->fd, "  Safe shutdown:              %s\n", batchsafeshutdown ? "Enabled" : "Disabled");
01428          ast_cli(a->fd, "  Threading model:            %s\n", batchscheduleronly ? "Scheduler only" : "Scheduler plus separate threads");
01429          ast_cli(a->fd, "  Current batch size:         %d record%s\n", cnt, ESS(cnt));
01430          ast_cli(a->fd, "  Maximum batch size:         %d record%s\n", batchsize, ESS(batchsize));
01431          ast_cli(a->fd, "  Maximum batch time:         %d second%s\n", batchtime, ESS(batchtime));
01432          ast_cli(a->fd, "  Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
01433       }
01434       ast_cli(a->fd, "* Registered Backends\n");
01435       ast_cli(a->fd, "  -------------------\n");
01436       AST_RWLIST_RDLOCK(&be_list);
01437       if (AST_RWLIST_EMPTY(&be_list)) {
01438          ast_cli(a->fd, "    (none)\n");
01439       } else {
01440          AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
01441             ast_cli(a->fd, "    %s\n", beitem->name);
01442          }
01443       }
01444       AST_RWLIST_UNLOCK(&be_list);
01445       ast_cli(a->fd, "\n");
01446    }
01447 
01448    return CLI_SUCCESS;
01449 }

static char* handle_cli_submit ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1451 of file cdr.c.

References ast_cli_args::argc, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, submit_unscheduled_batch(), and ast_cli_entry::usage.

01452 {
01453    switch (cmd) {
01454    case CLI_INIT:
01455       e->command = "cdr submit";
01456       e->usage =
01457          "Usage: cdr submit\n"
01458          "       Posts all pending batched CDR data to the configured CDR backend engine modules.\n";
01459       return NULL;
01460    case CLI_GENERATE:
01461       return NULL;
01462    }
01463    if (a->argc > 2)
01464       return CLI_SHOWUSAGE;
01465 
01466    submit_unscheduled_batch();
01467    ast_cli(a->fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
01468 
01469    return CLI_SUCCESS;
01470 }

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1234 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

01235 {
01236    /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
01237    if (!(batch = ast_malloc(sizeof(*batch))))
01238       return -1;
01239 
01240    reset_batch();
01241 
01242    return 0;
01243 }

static void post_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 1110 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_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_cdr_beitem::be, ast_cdr::channel, check_post(), ast_cdr::disposition, ast_cdr::dstchannel, ast_cdr_beitem::list, ast_cdr::next, and unanswered.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

01111 {
01112    struct ast_cdr_beitem *i;
01113 
01114    for ( ; cdr ; cdr = cdr->next) {
01115       if (!unanswered && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
01116          /* For people, who don't want to see unanswered single-channel events */
01117          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01118          continue;
01119       }
01120 
01121       /* don't post CDRs that are for dialed channels unless those
01122        * channels were originated from asterisk (pbx_spool, manager,
01123        * cli) */
01124       if (ast_test_flag(cdr, AST_CDR_FLAG_DIALED) && !ast_test_flag(cdr, AST_CDR_FLAG_ORIGINATED)) {
01125          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01126          continue;
01127       }
01128 
01129       check_post(cdr);
01130       ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
01131       if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
01132          continue;
01133       AST_RWLIST_RDLOCK(&be_list);
01134       AST_RWLIST_TRAVERSE(&be_list, i, list) {
01135          i->be(cdr);
01136       }
01137       AST_RWLIST_UNLOCK(&be_list);
01138    }
01139 }

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

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

01227 {
01228    batch->size = 0;
01229    batch->head = NULL;
01230    batch->tail = NULL;
01231 }

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

Definition at line 851 of file cdr.c.

References ast_party_caller::ani, ast_callerid_merge(), ast_cdr_setvar(), ast_copy_string(), ast_channel::caller, ast_cdr::clid, ast_channel::dialed, ast_party_caller::id, ast_party_id::name, ast_party_dialed::number, ast_party_id::number, S_COR, S_OR, ast_cdr::src, ast_party_subaddress::str, ast_party_dialed::str, ast_party_name::str, ast_party_number::str, ast_party_dialed::subaddress, ast_party_id::subaddress, ast_party_subaddress::valid, ast_party_name::valid, and ast_party_number::valid.

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

00852 {
00853    const char *num;
00854 
00855    if (!cdr) {
00856       return;
00857    }
00858 
00859    /* Grab source from ANI or normal Caller*ID */
00860    num = S_COR(c->caller.ani.number.valid, c->caller.ani.number.str,
00861       S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL));
00862    ast_callerid_merge(cdr->clid, sizeof(cdr->clid),
00863       S_COR(c->caller.id.name.valid, c->caller.id.name.str, NULL), num, "");
00864    ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src));
00865    ast_cdr_setvar(cdr, "dnid", S_OR(c->dialed.number.str, ""), 0);
00866 
00867    if (c->caller.id.subaddress.valid) {
00868       ast_cdr_setvar(cdr, "callingsubaddr", S_OR(c->caller.id.subaddress.str, ""), 0);
00869    }
00870    if (c->dialed.subaddress.valid) {
00871       ast_cdr_setvar(cdr, "calledsubaddr", S_OR(c->dialed.subaddress.str, ""), 0);
00872    }
00873 }

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

Definition at line 1292 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

01293 {
01294    ast_cdr_submit_batch(0);
01295    /* manually reschedule from this point in time */
01296    cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01297    /* returning zero so the scheduler does not automatically reschedule */
01298    return 0;
01299 }

static void submit_unscheduled_batch ( void   )  [static]

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

01302 {
01303    /* this is okay since we are not being called from within the scheduler */
01304    AST_SCHED_DEL(sched, cdr_sched);
01305    /* schedule the submission to occur ASAP (1 ms) */
01306    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
01307    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
01308    ast_mutex_lock(&cdr_pending_lock);
01309    ast_cond_signal(&cdr_pending_cond);
01310    ast_mutex_unlock(&cdr_pending_lock);
01311 }


Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]

Definition at line 56 of file cdr.c.

Referenced by __ast_channel_alloc_ap().

int ast_default_amaflags = AST_CDR_DOCUMENTATION

Default AMA flag for billing records (CDR's)

Definition at line 55 of file cdr.c.

Referenced by __ast_channel_alloc_ap(), and 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().

const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1 [static]

Definition at line 106 of file cdr.c.

Referenced by do_reload().

const int BATCH_SCHEDULER_ONLY_DEFAULT = 0 [static]

Definition at line 103 of file cdr.c.

Referenced by do_reload().

const int BATCH_SIZE_DEFAULT = 100 [static]

Definition at line 97 of file cdr.c.

Referenced by do_reload().

const int BATCH_TIME_DEFAULT = 300 [static]

Definition at line 100 of file cdr.c.

Referenced by do_reload().

int batchmode [static]

Definition at line 90 of file cdr.c.

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

const int BATCHMODE_DEFAULT = 0 [static]

Definition at line 91 of file cdr.c.

Referenced by do_reload().

int batchsafeshutdown [static]

Definition at line 105 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 102 of file cdr.c.

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

int batchsize [static]

Definition at line 96 of file cdr.c.

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

int batchtime [static]

Definition at line 99 of file cdr.c.

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

ast_mutex_t cdr_batch_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]

Definition at line 108 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 112 of file cdr.c.

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

ast_mutex_t cdr_pending_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]

Definition at line 111 of file cdr.c.

Referenced by do_cdr(), and submit_unscheduled_batch().

const char* const cdr_readonly_vars[] [static]

Initial value:

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

Definition at line 330 of file cdr.c.

Referenced by ast_cdr_data_add_structure(), ast_cdr_serialize_variables(), and ast_cdr_setvar().

int cdr_sched = -1 [static]

Definition at line 84 of file cdr.c.

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

int cdr_sequence = 0 [static]

Definition at line 79 of file cdr.c.

Referenced by cdr_seq_inc().

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 85 of file cdr.c.

Referenced by do_reload().

struct ast_cli_entry cli_status = { .handler = handle_cli_status , .summary = "Display the CDR status" ,__VA_ARGS__ } [static]

Definition at line 1473 of file cdr.c.

Referenced by ast_cdr_engine_init(), ast_cel_engine_init(), dnsmgr_init(), load_module(), and unload_module().

struct ast_cli_entry cli_submit = { .handler = handle_cli_submit , .summary = "Posts all pending batched CDR data" ,__VA_ARGS__ } [static]

Definition at line 1472 of file cdr.c.

Referenced by do_reload().

int enabled [static]

Definition at line 87 of file cdr.c.

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

const int ENABLED_DEFAULT = 1 [static]

Definition at line 88 of file cdr.c.

Referenced by do_reload().

struct sched_context* sched [static]

Definition at line 83 of file cdr.c.

int unanswered [static]

Definition at line 93 of file cdr.c.

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

const int UNANSWERED_DEFAULT = 0 [static]

Definition at line 94 of file cdr.c.

Referenced by do_reload().


Generated on Mon Mar 19 11:30:37 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7