Tue Aug 20 16:34:49 2013

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

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

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

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

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

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

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

Definition at line 1217 of file cdr.c.

References ast_cdr::next.

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

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

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

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

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

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

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

int ast_cdr_engine_init ( void   ) 

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

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

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

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1669 of file cdr.c.

References do_reload().

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

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1664 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by can_safely_quit(), and do_reload().

01665 {
01666    ast_cdr_submit_batch(batchsafeshutdown);
01667 }

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

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

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

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

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

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

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

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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) {
00376          newvariable = ast_var_assign(name, value);
00377          AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00378       }
00379    }
00380 
00381    return 0;
00382 }

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

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

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

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

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

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

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

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

static void cdr_engine_shutdown ( void   )  [static]

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

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

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

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

static int cdr_seq_inc ( struct ast_cdr cdr  )  [static]

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

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

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

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

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

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

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

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

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

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

static void do_reload ( int  reload  )  [static]

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

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

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

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

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

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

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

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

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

Definition at line 1243 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach().

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

static void post_cdr ( struct ast_cdr cdr  )  [static]

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

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

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

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

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

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

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

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

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

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

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

static void submit_unscheduled_batch ( void   )  [static]

Do not hold the batch lock while calling this function

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

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


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 1496 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 1495 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 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1