Mon Aug 31 12:30:21 2015

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

struct 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.
struct 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)
 the same as a cdr_free call, only with no checks; just get rid of it
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_*.
struct ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a record.
struct ast_cdrast_cdr_dup_unique (struct ast_cdr *cdr)
 Duplicate a record and increment the sequence number.
struct 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 driver. Each registered CDR driver generates a CDR.
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_engine_shutdown (void)
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 void 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 ast_mutex_t cdr_sched_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static int cdr_sequence = 0
static pthread_t cdr_thread = AST_PTHREADT_NULL
static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CDR status")
static struct ast_cli_entry cli_submit = AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data")
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   )  [read]

Allocate a CDR record.

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

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

00500 {
00501    struct ast_cdr *x;
00502    x = ast_calloc(1, sizeof(*x));
00503    if (!x)
00504       ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
00505    return x;
00506 }

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

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

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

01106 {
01107    if (!strcasecmp(flag, "default"))
01108       return 0;
01109    if (!strcasecmp(flag, "omit"))
01110       return AST_CDR_OMIT;
01111    if (!strcasecmp(flag, "billing"))
01112       return AST_CDR_BILLING;
01113    if (!strcasecmp(flag, "documentation"))
01114       return AST_CDR_DOCUMENTATION;
01115    return -1;
01116 }

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

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

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

00738 {
00739 
00740    for (; cdr; cdr = cdr->next) {
00741       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
00742          continue;
00743       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00744          continue;
00745       check_post(cdr);
00746       if (cdr->disposition < AST_CDR_ANSWERED)
00747          cdr->disposition = AST_CDR_ANSWERED;
00748       if (ast_tvzero(cdr->answer))
00749          cdr->answer = ast_tvnow();
00750    }
00751 }

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

Definition at line 1216 of file cdr.c.

References ast_cdr::next.

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

01217 {
01218    struct ast_cdr *ret;
01219 
01220    if (cdr) {
01221       ret = cdr;
01222 
01223       while (cdr->next)
01224          cdr = cdr->next;
01225       cdr->next = newcdr;
01226    } else {
01227       ret = newcdr;
01228    }
01229 
01230    return ret;
01231 }

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

01070 {
01071    struct ast_cdr *cdr = chan->cdr;
01072 
01073    for ( ; cdr ; cdr = cdr->next) {
01074       int len = strlen(cdr->userfield);
01075 
01076       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
01077          ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
01078    }
01079 
01080    return 0;
01081 }

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

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

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

00754 {
00755 
00756    for (; cdr; cdr = cdr->next) {
00757       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00758          check_post(cdr);
00759          cdr->disposition = AST_CDR_BUSY;
00760       }
00761    }
00762 }

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

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

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 1674 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_cdr::next, var, and ast_cdr::varshead.

Referenced by ast_channel_data_add_structure().

01675 {
01676    struct ast_cdr *tmpcdr;
01677    struct ast_data *level;
01678    struct ast_var_t *variables;
01679    const char *var, *val;
01680    int x = 1, i;
01681    char workspace[256];
01682    char *tmp;
01683 
01684    if (!cdr) {
01685       return -1;
01686    }
01687 
01688    for (tmpcdr = cdr; tmpcdr; tmpcdr = (recur ? tmpcdr->next : NULL)) {
01689       level = ast_data_add_node(tree, "level");
01690       if (!level) {
01691          continue;
01692       }
01693 
01694       ast_data_add_int(level, "level_number", x);
01695 
01696       AST_LIST_TRAVERSE(&tmpcdr->varshead, variables, entries) {
01697          if (variables && (var = ast_var_name(variables)) &&
01698                (val = ast_var_value(variables)) && !ast_strlen_zero(var)
01699                && !ast_strlen_zero(val)) {
01700             ast_data_add_str(level, var, val);
01701          } else {
01702             break;
01703          }
01704       }
01705 
01706       for (i = 0; cdr_readonly_vars[i]; i++) {
01707          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 */
01708          ast_cdr_getvar(tmpcdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
01709          if (!tmp) {
01710             continue;
01711          }
01712          ast_data_add_str(level, cdr_readonly_vars[i], tmp);
01713       }
01714 
01715       x++;
01716    }
01717 
01718    return 0;
01719 }

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

01329 {
01330    struct ast_cdr_batch_item *newtail;
01331    int curr;
01332    int submit_batch = 0;
01333 
01334    if (!cdr)
01335       return;
01336 
01337    /* maybe they disabled CDR stuff completely, so just drop it */
01338    if (!enabled) {
01339       ast_debug(1, "Dropping CDR !\n");
01340       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01341       ast_cdr_free(cdr);
01342       return;
01343    }
01344 
01345    /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
01346    if (!batchmode) {
01347       post_cdr(cdr);
01348       ast_cdr_free(cdr);
01349       return;
01350    }
01351 
01352    /* otherwise, each CDR gets put into a batch list (at the end) */
01353    ast_debug(1, "CDR detaching from this thread\n");
01354 
01355    /* we'll need a new tail for every CDR */
01356    if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
01357       post_cdr(cdr);
01358       ast_cdr_free(cdr);
01359       return;
01360    }
01361 
01362    /* don't traverse a whole list (just keep track of the tail) */
01363    ast_mutex_lock(&cdr_batch_lock);
01364    if (!batch)
01365       init_batch();
01366    if (!batch->head) {
01367       /* new batch is empty, so point the head at the new tail */
01368       batch->head = newtail;
01369    } else {
01370       /* already got a batch with something in it, so just append a new tail */
01371       batch->tail->next = newtail;
01372    }
01373    newtail->cdr = cdr;
01374    batch->tail = newtail;
01375    curr = batch->size++;
01376 
01377    /* if we have enough stuff to post, then do it */
01378    if (curr >= (batchsize - 1)) {
01379       submit_batch = 1;
01380    }
01381    ast_mutex_unlock(&cdr_batch_lock);
01382 
01383    /* Don't call submit_unscheduled_batch with the cdr_batch_lock held */
01384    if (submit_batch) {
01385       submit_unscheduled_batch();
01386    }
01387 }

void ast_cdr_discard ( struct ast_cdr cdr  ) 

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

Discard and free a CDR record.

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

00489 {
00490    while (cdr) {
00491       struct ast_cdr *next = cdr->next;
00492 
00493       ast_cdr_free_vars(cdr, 0);
00494       ast_free(cdr);
00495       cdr = next;
00496    }
00497 }

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

00960 {
00961    switch (disposition) {
00962    case AST_CDR_NULL:
00963       return "NO ANSWER"; /* by default, for backward compatibility */
00964    case AST_CDR_NOANSWER:
00965       return "NO ANSWER";
00966    case AST_CDR_FAILED:
00967       return "FAILED";
00968    case AST_CDR_BUSY:
00969       return "BUSY";
00970    case AST_CDR_ANSWERED:
00971       return "ANSWERED";
00972    }
00973    return "UNKNOWN";
00974 }

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

00791 {
00792    int res = 0;
00793 
00794    for (; cdr; cdr = cdr->next) {
00795       switch (cause) {  /* handle all the non failure, busy cases, return 0 not to set disposition,
00796                      return -1 to set disposition to FAILED */
00797       case AST_CAUSE_BUSY:
00798          ast_cdr_busy(cdr);
00799          break;
00800       case AST_CAUSE_NO_ANSWER:
00801          ast_cdr_noanswer(cdr);
00802          break;
00803       case AST_CAUSE_NORMAL:
00804          break;
00805       default:
00806          res = -1;
00807       }
00808    }
00809    return res;
00810 }

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

Duplicate a record.

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 213 of file cdr.c.

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

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

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

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

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

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_cdr_fork().

00191 {
00192    struct ast_cdr *newcdr = ast_cdr_dup(cdr);
00193    if (!newcdr)
00194       return NULL;
00195 
00196    cdr_seq_inc(newcdr);
00197    return newcdr;
00198 }

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

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

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_bridge_call(), and ast_cdr_reset().

00201 {
00202    struct ast_cdr *newcdr = ast_cdr_dup(cdr);
00203    if (!newcdr)
00204       return NULL;
00205 
00206    cdr_seq_inc(cdr);
00207    return newcdr;
00208 }

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

References ast_cdr::answer, AST_CDR_ANSWERED, AST_CDR_FAILED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_log(), AST_OPT_FLAG_INITIATED_SECONDS, ast_options, ast_test_flag, ast_tvnow(), ast_tvzero(), ast_cdr::billsec, ast_cdr::channel, check_post(), ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, LOG_WARNING, ast_cdr::next, S_OR, and ast_cdr::start.

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

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

int ast_cdr_engine_init ( void   ) 

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

Definition at line 1646 of file cdr.c.

References ast_cli_register(), ast_log(), ast_register_atexit(), cdr_engine_shutdown(), cli_status, do_reload(), LOG_ERROR, and sched_context_create().

Referenced by main().

01647 {
01648    sched = sched_context_create();
01649    if (!sched) {
01650       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
01651       return -1;
01652    }
01653 
01654    ast_cli_register(&cli_status);
01655    do_reload(0);
01656    ast_register_atexit(cdr_engine_shutdown);
01657 
01658    return 0;
01659 }

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1668 of file cdr.c.

References do_reload().

01669 {
01670    do_reload(1);
01671    return 0;
01672 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1663 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by can_safely_quit(), and do_reload().

01664 {
01665    ast_cdr_submit_batch(batchsafeshutdown);
01666 }

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

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

Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten(), clear_caller(), findmeexec(), handle_cause(), try_calling(), and wait_for_answer().

00765 {
00766    for (; cdr; cdr = cdr->next) {
00767       check_post(cdr);
00768       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00769          check_post(cdr);
00770          if (cdr->disposition < AST_CDR_FAILED)
00771             cdr->disposition = AST_CDR_FAILED;
00772       }
00773    }
00774 }

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

00978 {
00979    switch (flag) {
00980    case AST_CDR_OMIT:
00981       return "OMIT";
00982    case AST_CDR_BILLING:
00983       return "BILLING";
00984    case AST_CDR_DOCUMENTATION:
00985       return "DOCUMENTATION";
00986    }
00987    return "Unknown";
00988 }

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

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

00476 {
00477 
00478    while (cdr) {
00479       struct ast_cdr *next = cdr->next;
00480 
00481       ast_cdr_free_vars(cdr, 0);
00482       ast_free(cdr);
00483       cdr = next;
00484    }
00485 }

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

00455 {
00456 
00457    /* clear variables */
00458    for (; cdr; cdr = recur ? cdr->next : NULL) {
00459       struct ast_var_t *vardata;
00460       struct varshead *headp = &cdr->varshead;
00461       while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
00462          ast_var_delete(vardata);
00463    }
00464 }

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 264 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_tvzero(), 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().

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

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

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

00233 {
00234    if (ast_strlen_zero(name))
00235       return NULL;
00236 
00237    for (; cdr; cdr = recur ? cdr->next : NULL) {
00238       struct ast_var_t *variables;
00239       struct varshead *headp = &cdr->varshead;
00240       AST_LIST_TRAVERSE(headp, variables, entries) {
00241          if (!strcasecmp(name, ast_var_name(variables)))
00242             return ast_var_value(variables);
00243       }
00244    }
00245 
00246    return NULL;
00247 }

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

References ast_channel::_state, ast_cdr::accountcode, ast_channel::amaflags, ast_cdr::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_copy_string(), AST_STATE_UP, ast_test_flag, cdr_seq_inc(), ast_cdr::channel, ast_channel::context, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_channel::exten, ast_cdr::linkedid, ast_channel::macrocontext, ast_channel::macroexten, ast_cdr::next, ast_cdr::peeraccount, S_OR, set_one_cid(), and ast_cdr::uniqueid.

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

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

int ast_cdr_isset_unanswered ( void   ) 

Definition at line 185 of file cdr.c.

References unanswered.

Referenced by ring_entry(), and try_calling().

00186 {
00187    return unanswered;
00188 }

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

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

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

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

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

00777 {
00778    while (cdr) {
00779       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00780          check_post(cdr);
00781          cdr->disposition = AST_CDR_NOANSWER;
00782       }
00783       cdr = cdr->next;
00784    }
00785 }

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

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

Register a CDR handling engine.

Return values:
0 on success.
-1 on error

Definition at line 130 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::be, ast_cdr_beitem::desc, ast_cdr_beitem::list, LOG_WARNING, and ast_cdr_beitem::name.

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

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

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

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

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

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

Definition at line 409 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, LOG_ERROR, ast_cdr::next, S_OR, total, var, and ast_cdr::varshead.

Referenced by handle_showchan().

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

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

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

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

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

01043 {
01044    struct ast_cdr *cdr;
01045    int newflag = ast_cdr_amaflags2int(flag);
01046    if (newflag) {
01047       for (cdr = chan->cdr; cdr; cdr = cdr->next) {
01048          if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01049             cdr->amaflags = newflag;
01050          }
01051       }
01052    }
01053 
01054    return 0;
01055 }

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

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

Referenced by ast_bridge_call(), and dial_exec_full().

00835 {
00836 
00837    for (; cdr; cdr = cdr->next) {
00838       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
00839          continue;
00840       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00841          continue;
00842       check_post(cdr);
00843       cdr->answer = t;
00844    }
00845 }

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

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

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

00823 {
00824 
00825    for (; cdr; cdr = cdr->next) {
00826       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00827          check_post(cdr);
00828          ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp));
00829          ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata));
00830       }
00831    }
00832 }

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

00884 {
00885    for (; cdr; cdr = cdr->next) {
00886       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00887          set_one_cid(cdr, c);
00888    }
00889    return 0;
00890 }

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

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

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

00813 {
00814    for (; cdr; cdr = cdr->next) {
00815       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00816          check_post(cdr);
00817          ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
00818       }
00819    }
00820 }

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

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

Referenced by ast_bridge_call().

00848 {
00849 
00850    for (; cdr; cdr = cdr->next) {
00851       if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00852          continue;
00853       check_post(cdr);
00854       cdr->disposition = disposition;
00855    }
00856 }

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 1016 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, and ast_cdr::peeraccount.

Referenced by cdr_write().

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

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

01058 {
01059    struct ast_cdr *cdr = chan->cdr;
01060 
01061    for ( ; cdr ; cdr = cdr->next) {
01062       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
01063          ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
01064    }
01065 
01066    return 0;
01067 }

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

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

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

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

void ast_cdr_specialized_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

Reset the detail record times, flags

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

Definition at line 1192 of file cdr.c.

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

Referenced by ast_bridge_call().

01193 {
01194    struct ast_flags flags = { 0 };
01195 
01196    if (_flags)
01197       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
01198 
01199    /* Reset to initial state */
01200    if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) { /* But do NOT lose the NoCDR() setting */
01201       ast_clear_flag(cdr, AST_FLAGS_ALL);
01202       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01203    } else {
01204       ast_clear_flag(cdr, AST_FLAGS_ALL);
01205    }
01206 
01207    memset(&cdr->start, 0, sizeof(cdr->start));
01208    memset(&cdr->end, 0, sizeof(cdr->end));
01209    memset(&cdr->answer, 0, sizeof(cdr->answer));
01210    cdr->billsec = 0;
01211    cdr->duration = 0;
01212    ast_cdr_start(cdr);
01213    cdr->disposition = AST_CDR_NULL;
01214 }

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

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

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

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

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

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

void ast_cdr_unregister ( const char *  name  ) 

Unregister a CDR handling engine.

unregister a CDR driver

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

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

int ast_cdr_update ( struct ast_channel chan  ) 

Update CDR on a channel.

Note:
The channel should be locked before calling.

Definition at line 1083 of file cdr.c.

References ast_cdr::accountcode, AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, ast_channel::context, ast_cdr::dcontext, ast_cdr::dst, ast_channel::exten, ast_cdr::linkedid, ast_channel::macrocontext, ast_channel::macroexten, ast_cdr::next, ast_cdr::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().

01084 {
01085    struct ast_cdr *cdr = c->cdr;
01086 
01087    for ( ; cdr ; cdr = cdr->next) {
01088       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
01089          set_one_cid(cdr, c);
01090 
01091          /* Copy account code et-al */
01092          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
01093          ast_copy_string(cdr->peeraccount, c->peeraccount, sizeof(cdr->peeraccount));
01094          ast_copy_string(cdr->linkedid, c->linkedid, sizeof(cdr->linkedid));
01095 
01096          /* Destination information */ /* XXX privilege macro* ? */
01097          ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst));
01098          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext));
01099       }
01100    }
01101 
01102    return 0;
01103 }

static void cdr_engine_shutdown ( void   )  [static]

Definition at line 1627 of file cdr.c.

References ast_cli_unregister(), ast_cond_destroy, ast_free, AST_PTHREADT_NULL, batch, cdr_pending_cond, cdr_thread, cli_status, cli_submit, and sched_context_destroy().

Referenced by ast_cdr_engine_init().

01628 {
01629    if (cdr_thread != AST_PTHREADT_NULL) {
01630       /* wake up the thread so it will exit */
01631       pthread_cancel(cdr_thread);
01632       pthread_kill(cdr_thread, SIGURG);
01633       pthread_join(cdr_thread, NULL);
01634       cdr_thread = AST_PTHREADT_NULL;
01635       ast_cond_destroy(&cdr_pending_cond);
01636    }
01637    ast_cli_unregister(&cli_submit);
01638 
01639    ast_cli_unregister(&cli_status);
01640    sched_context_destroy(sched);
01641    sched = NULL;
01642    ast_free(batch);
01643    batch = NULL;
01644 }

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

Definition at line 249 of file cdr.c.

References ast_localtime(), and ast_strftime().

Referenced by ast_cdr_getvar().

00250 {
00251    if (fmt == NULL) {   /* raw mode */
00252       snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
00253    } else {
00254       if (when.tv_sec) {
00255          struct ast_tm tm;
00256 
00257          ast_localtime(&when, &tm, NULL);
00258          ast_strftime(buf, bufsize, fmt, &tm);
00259       }
00260    }
00261 }

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

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

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

static int cdr_seq_inc ( struct ast_cdr cdr  )  [static]

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

00893 {
00894    return (cdr->sequence = ast_atomic_fetchadd_int(&cdr_sequence, +1));
00895 }

int check_cdr_enabled ( void   ) 

Return TRUE if CDR subsystem is enabled.

Definition at line 120 of file cdr.c.

References enabled.

Referenced by action_coresettings(), and handle_show_settings().

00121 {
00122    return enabled;
00123 }

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

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

00468 {
00469    if (!cdr)
00470       return;
00471    if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
00472       ast_log(LOG_NOTICE, "CDR on channel '%s' already posted\n", S_OR(cdr->channel, "<unknown>"));
00473 }

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

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

01254 {
01255    struct ast_cdr_batch_item *processeditem;
01256    struct ast_cdr_batch_item *batchitem = data;
01257 
01258    /* Push each CDR into storage mechanism(s) and free all the memory */
01259    while (batchitem) {
01260       post_cdr(batchitem->cdr);
01261       ast_cdr_free(batchitem->cdr);
01262       processeditem = batchitem;
01263       batchitem = batchitem->next;
01264       ast_free(processeditem);
01265    }
01266 
01267    return NULL;
01268 }

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

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

01390 {
01391    struct timespec timeout;
01392    int schedms;
01393    int numevents = 0;
01394 
01395    for (;;) {
01396       struct timeval now;
01397       schedms = ast_sched_wait(sched);
01398       /* this shouldn't happen, but provide a 1 second default just in case */
01399       if (schedms <= 0)
01400          schedms = 1000;
01401       now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
01402       timeout.tv_sec = now.tv_sec;
01403       timeout.tv_nsec = now.tv_usec * 1000;
01404       /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
01405       ast_mutex_lock(&cdr_pending_lock);
01406       ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
01407       numevents = ast_sched_runq(sched);
01408       ast_mutex_unlock(&cdr_pending_lock);
01409       ast_debug(2, "Processed %d scheduled CDR batches from the run queue\n", numevents);
01410    }
01411 
01412    return NULL;
01413 }

static void do_reload ( int  reload  )  [static]

Definition at line 1497 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_sched_lock, cdr_thread, cli_submit, config, CONFIG_FLAG_FILEUNCHANGED, 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(), and ast_cdr_engine_reload().

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

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

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

01416 {
01417    struct ast_cdr_beitem *beitem=NULL;
01418    int cnt=0;
01419    long nextbatchtime=0;
01420 
01421    switch (cmd) {
01422    case CLI_INIT:
01423       e->command = "cdr show status";
01424       e->usage =
01425          "Usage: cdr show status\n"
01426          "  Displays the Call Detail Record engine system status.\n";
01427       return NULL;
01428    case CLI_GENERATE:
01429       return NULL;
01430    }
01431 
01432    if (a->argc > 3)
01433       return CLI_SHOWUSAGE;
01434 
01435    ast_cli(a->fd, "\n");
01436    ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
01437    ast_cli(a->fd, "----------------------------------\n");
01438    ast_cli(a->fd, "  Logging:                    %s\n", enabled ? "Enabled" : "Disabled");
01439    ast_cli(a->fd, "  Mode:                       %s\n", batchmode ? "Batch" : "Simple");
01440    if (enabled) {
01441       ast_cli(a->fd, "  Log unanswered calls:       %s\n\n", unanswered ? "Yes" : "No");
01442       if (batchmode) {
01443          ast_cli(a->fd, "* Batch Mode Settings\n");
01444          ast_cli(a->fd, "  -------------------\n");
01445          if (batch)
01446             cnt = batch->size;
01447          if (cdr_sched > -1)
01448             nextbatchtime = ast_sched_when(sched, cdr_sched);
01449          ast_cli(a->fd, "  Safe shutdown:              %s\n", batchsafeshutdown ? "Enabled" : "Disabled");
01450          ast_cli(a->fd, "  Threading model:            %s\n", batchscheduleronly ? "Scheduler only" : "Scheduler plus separate threads");
01451          ast_cli(a->fd, "  Current batch size:         %d record%s\n", cnt, ESS(cnt));
01452          ast_cli(a->fd, "  Maximum batch size:         %d record%s\n", batchsize, ESS(batchsize));
01453          ast_cli(a->fd, "  Maximum batch time:         %d second%s\n", batchtime, ESS(batchtime));
01454          ast_cli(a->fd, "  Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
01455       }
01456       ast_cli(a->fd, "* Registered Backends\n");
01457       ast_cli(a->fd, "  -------------------\n");
01458       AST_RWLIST_RDLOCK(&be_list);
01459       if (AST_RWLIST_EMPTY(&be_list)) {
01460          ast_cli(a->fd, "    (none)\n");
01461       } else {
01462          AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
01463             ast_cli(a->fd, "    %s\n", beitem->name);
01464          }
01465       }
01466       AST_RWLIST_UNLOCK(&be_list);
01467       ast_cli(a->fd, "\n");
01468    }
01469 
01470    return CLI_SUCCESS;
01471 }

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

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

01474 {
01475    switch (cmd) {
01476    case CLI_INIT:
01477       e->command = "cdr submit";
01478       e->usage =
01479          "Usage: cdr submit\n"
01480          "       Posts all pending batched CDR data to the configured CDR backend engine modules.\n";
01481       return NULL;
01482    case CLI_GENERATE:
01483       return NULL;
01484    }
01485    if (a->argc > 2)
01486       return CLI_SHOWUSAGE;
01487 
01488    submit_unscheduled_batch();
01489    ast_cli(a->fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
01490 
01491    return CLI_SUCCESS;
01492 }

static int init_batch ( void   )  [static]
Note:
Don't call without cdr_batch_lock

Definition at line 1242 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach().

01243 {
01244    /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
01245    if (!(batch = ast_malloc(sizeof(*batch))))
01246       return -1;
01247 
01248    reset_batch();
01249 
01250    return 0;
01251 }

static void post_cdr ( struct ast_cdr cdr  )  [static]

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

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

static void reset_batch ( void   )  [static]
Note:
Don't call without cdr_batch_lock

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

01235 {
01236    batch->size = 0;
01237    batch->head = NULL;
01238    batch->tail = NULL;
01239 }

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

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

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

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

Definition at line 1300 of file cdr.c.

References ast_cdr_submit_batch(), ast_mutex_lock, ast_mutex_unlock, ast_sched_add(), batchtime, cdr_sched, and cdr_sched_lock.

Referenced by do_reload(), and submit_unscheduled_batch().

01301 {
01302    ast_cdr_submit_batch(0);
01303    /* manually reschedule from this point in time */
01304    ast_mutex_lock(&cdr_sched_lock);
01305    cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01306    ast_mutex_unlock(&cdr_sched_lock);
01307    /* returning zero so the scheduler does not automatically reschedule */
01308    return 0;
01309 }

static void submit_unscheduled_batch ( void   )  [static]

Do not hold the batch lock while calling this function

Definition at line 1312 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, cdr_sched_lock, and submit_scheduled_batch().

Referenced by ast_cdr_detach(), and handle_cli_submit().

01313 {
01314    /* Prevent two deletes from happening at the same time */
01315    ast_mutex_lock(&cdr_sched_lock);
01316    /* this is okay since we are not being called from within the scheduler */
01317    AST_SCHED_DEL(sched, cdr_sched);
01318    /* schedule the submission to occur ASAP (1 ms) */
01319    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
01320    ast_mutex_unlock(&cdr_sched_lock);
01321 
01322    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
01323    ast_mutex_lock(&cdr_pending_lock);
01324    ast_cond_signal(&cdr_pending_cond);
01325    ast_mutex_unlock(&cdr_pending_lock);
01326 }


Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]

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

Referenced by __ast_channel_alloc_ap(), and ast_bridge_call().

struct ast_cdr_batch * batch [static]
const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1 [static]

Definition at line 110 of file cdr.c.

Referenced by do_reload().

const int BATCH_SCHEDULER_ONLY_DEFAULT = 0 [static]

Definition at line 107 of file cdr.c.

Referenced by do_reload().

const int BATCH_SIZE_DEFAULT = 100 [static]

Definition at line 101 of file cdr.c.

Referenced by do_reload().

const int BATCH_TIME_DEFAULT = 300 [static]

Definition at line 104 of file cdr.c.

Referenced by do_reload().

int batchmode [static]

Definition at line 94 of file cdr.c.

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

const int BATCHMODE_DEFAULT = 0 [static]

Definition at line 95 of file cdr.c.

Referenced by do_reload().

int batchsafeshutdown [static]

Definition at line 109 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 106 of file cdr.c.

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

int batchsize [static]

Definition at line 100 of file cdr.c.

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

int batchtime [static]

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

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

Definition at line 118 of file cdr.c.

Referenced by cdr_engine_shutdown(), 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 117 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 336 of file cdr.c.

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

int cdr_sched = -1 [static]
ast_mutex_t cdr_sched_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]

Definition at line 112 of file cdr.c.

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

int cdr_sequence = 0 [static]

Definition at line 83 of file cdr.c.

Referenced by cdr_seq_inc().

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 89 of file cdr.c.

Referenced by cdr_engine_shutdown(), and do_reload().

struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CDR status") [static]

Definition at line 1495 of file cdr.c.

Referenced by ast_cdr_engine_init(), and cdr_engine_shutdown().

struct ast_cli_entry cli_submit = AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data") [static]

Definition at line 1494 of file cdr.c.

Referenced by cdr_engine_shutdown(), and do_reload().

int enabled [static]
const int ENABLED_DEFAULT = 1 [static]

Definition at line 92 of file cdr.c.

Referenced by do_reload().

struct sched_context* sched [static]

Definition at line 87 of file cdr.c.

int unanswered [static]

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

Referenced by do_reload().


Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1