Mon Jun 27 16:51:03 2011

Asterisk developer's documentation


cdr.c File Reference

Call Detail Record API. More...

#include "asterisk.h"
#include <signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/callerid.h"
#include "asterisk/manager.h"
#include "asterisk/causes.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.h"
#include "asterisk/sched.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"
#include "asterisk/data.h"

Go to the source code of this file.

Data Structures

struct  ast_cdr_batch
struct  ast_cdr_batch_item
struct  ast_cdr_beitem
struct  be_list

Functions

ast_cdrast_cdr_alloc (void)
 Allocate a CDR record.
int ast_cdr_amaflags2int (const char *flag)
 Convert a string to a detail record AMA flag.
void ast_cdr_answer (struct ast_cdr *cdr)
 Answer a call.
ast_cdrast_cdr_append (struct ast_cdr *cdr, struct ast_cdr *newcdr)
int ast_cdr_appenduserfield (struct ast_channel *chan, const char *userfield)
 Append to CDR user field for channel (stored in CDR).
void ast_cdr_busy (struct ast_cdr *cdr)
 Busy a call.
int ast_cdr_copy_vars (struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
int ast_cdr_data_add_structure (struct ast_data *tree, struct ast_cdr *cdr, int recur)
void ast_cdr_detach (struct ast_cdr *cdr)
 Detaches the detail record for posting (and freeing) either now or at a later time in bulk with other records during batch mode operation.
void ast_cdr_discard (struct ast_cdr *cdr)
 Discard and free a CDR record.
char * ast_cdr_disp2str (int disposition)
 Disposition to a string.
int ast_cdr_disposition (struct ast_cdr *cdr, int cause)
 Save the result of the call based on the AST_CAUSE_*.
ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a record.
ast_cdrast_cdr_dup_unique (struct ast_cdr *cdr)
 Duplicate a record and increment the sequence number.
ast_cdrast_cdr_dup_unique_swap (struct ast_cdr *cdr)
 Duplicate a record and increment the sequence number of the old record.
void ast_cdr_end (struct ast_cdr *cdr)
 End a call.
int ast_cdr_engine_init (void)
 Load the configuration file cdr.conf and possibly start the CDR scheduling thread.
int ast_cdr_engine_reload (void)
 Reload the configuration file cdr.conf and start/stop CDR scheduling thread.
void ast_cdr_engine_term (void)
void ast_cdr_failed (struct ast_cdr *cdr)
 Fail a call.
char * ast_cdr_flags2str (int flag)
void ast_cdr_free (struct ast_cdr *cdr)
 Free a CDR record.
void ast_cdr_free_vars (struct ast_cdr *cdr, int recur)
void ast_cdr_getvar (struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw)
static const char * ast_cdr_getvar_internal (struct ast_cdr *cdr, const char *name, int recur)
int ast_cdr_init (struct ast_cdr *cdr, struct ast_channel *c)
 Initialize based on a channel.
int ast_cdr_isset_unanswered (void)
void ast_cdr_merge (struct ast_cdr *to, struct ast_cdr *from)
 Move the non-null data from the "from" cdr to the "to" cdr.
void ast_cdr_noanswer (struct ast_cdr *cdr)
 A call wasn't answered.
int ast_cdr_register (const char *name, const char *desc, ast_cdrbe be)
 Register a CDR handling engine.
void ast_cdr_reset (struct ast_cdr *cdr, struct ast_flags *_flags)
 Reset the detail record, optionally posting it first.
int ast_cdr_serialize_variables (struct ast_cdr *cdr, struct ast_str **buf, char delim, char sep, int recur)
int ast_cdr_setaccount (struct ast_channel *chan, const char *account)
 Set account code, will generate AMI event.
int ast_cdr_setamaflags (struct ast_channel *chan, const char *flag)
 Set AMA flags for channel.
void ast_cdr_setanswer (struct ast_cdr *cdr, struct timeval t)
 Set the answer time for a call.
void ast_cdr_setapp (struct ast_cdr *cdr, const char *app, const char *data)
 Set the last executed application.
int ast_cdr_setcid (struct ast_cdr *cdr, struct ast_channel *c)
 Initialize based on a channel.
void ast_cdr_setdestchan (struct ast_cdr *cdr, const char *chann)
 Set the destination channel, if there was one.
void ast_cdr_setdisposition (struct ast_cdr *cdr, long int disposition)
 Set the disposition for a call.
int ast_cdr_setpeeraccount (struct ast_channel *chan, const char *account)
 Set the peer account.
int ast_cdr_setuserfield (struct ast_channel *chan, const char *userfield)
 Set CDR user field for channel (stored in CDR).
int ast_cdr_setvar (struct ast_cdr *cdr, const char *name, const char *value, int recur)
void ast_cdr_specialized_reset (struct ast_cdr *cdr, struct ast_flags *_flags)
void ast_cdr_start (struct ast_cdr *cdr)
 Start a call.
void ast_cdr_submit_batch (int do_shutdown)
 Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines.
void ast_cdr_unregister (const char *name)
 Unregister a CDR handling engine.
int ast_cdr_update (struct ast_channel *c)
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 ()
 Return TRUE if CDR subsystem is enabled.
static void check_post (struct ast_cdr *cdr)
 print a warning if cdr already posted
static void * do_batch_backend_process (void *data)
static void * do_cdr (void *data)
static int do_reload (int reload)
static char * handle_cli_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_submit (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int init_batch (void)
static void post_cdr (struct ast_cdr *cdr)
static void reset_batch (void)
static void set_one_cid (struct ast_cdr *cdr, struct ast_channel *c)
static int submit_scheduled_batch (const void *data)
static void submit_unscheduled_batch (void)

Variables

char ast_default_accountcode [AST_MAX_ACCOUNT_CODE]
int ast_default_amaflags = AST_CDR_DOCUMENTATION
static struct ast_cdr_batchbatch
static const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1
static const int BATCH_SCHEDULER_ONLY_DEFAULT = 0
static const int BATCH_SIZE_DEFAULT = 100
static const int BATCH_TIME_DEFAULT = 300
static int batchmode
static const int BATCHMODE_DEFAULT = 0
static int batchsafeshutdown
static int batchscheduleronly
static int batchsize
static int batchtime
static ast_mutex_t cdr_batch_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static ast_cond_t cdr_pending_cond
static ast_mutex_t cdr_pending_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static const char *const cdr_readonly_vars []
static int cdr_sched = -1
static int cdr_sequence = 0
static pthread_t cdr_thread = AST_PTHREADT_NULL
static struct ast_cli_entry cli_status = { .handler = handle_cli_status , .summary = "Display the CDR status" ,__VA_ARGS__ }
static struct ast_cli_entry cli_submit = { .handler = handle_cli_submit , .summary = "Posts all pending batched CDR data" ,__VA_ARGS__ }
static int enabled
static const int ENABLED_DEFAULT = 1
static struct sched_contextsched
static int unanswered
static const int UNANSWERED_DEFAULT = 0


Detailed Description

Call Detail Record API.

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

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

Definition in file cdr.c.


Function Documentation

struct ast_cdr* ast_cdr_alloc ( void   ) 

Allocate a CDR record.

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

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

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

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

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

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

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

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

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

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

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

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

Definition at line 1217 of file cdr.c.

References ast_cdr::next.

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

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

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

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

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

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

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

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

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

Definition at line 376 of file cdr.c.

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

Referenced by ast_cdr_dup().

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

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

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

Referenced by ast_channel_data_add_structure().

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

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

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

void ast_cdr_discard ( struct ast_cdr cdr  ) 

Discard and free a CDR record.

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

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

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

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

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

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

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

struct ast_cdr* ast_cdr_dup ( struct ast_cdr cdr  ) 

Duplicate a record.

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 205 of file cdr.c.

References ast_cdr_alloc(), and ast_cdr_copy_vars().

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

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

struct ast_cdr* ast_cdr_dup_unique ( struct ast_cdr cdr  ) 

Duplicate a record and increment the sequence number.

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

ast_cdr_dup_unique_swap()

Definition at line 182 of file cdr.c.

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_cdr_fork().

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

struct ast_cdr* ast_cdr_dup_unique_swap ( struct ast_cdr cdr  ) 

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

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

ast_cdr_dup_unique()

Definition at line 192 of file cdr.c.

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_bridge_call(), and ast_cdr_reset().

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

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

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

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

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

int ast_cdr_engine_init ( void   ) 

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

Definition at line 1615 of file cdr.c.

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

Referenced by main().

01616 {
01617    int res;
01618 
01619    sched = sched_context_create();
01620    if (!sched) {
01621       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
01622       return -1;
01623    }
01624 
01625    ast_cli_register(&cli_status);
01626 
01627    res = do_reload(0);
01628    if (res) {
01629       ast_mutex_lock(&cdr_batch_lock);
01630       res = init_batch();
01631       ast_mutex_unlock(&cdr_batch_lock);
01632    }
01633 
01634    return res;
01635 }

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1644 of file cdr.c.

References do_reload().

01645 {
01646    return do_reload(1);
01647 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1639 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01640 {
01641    ast_cdr_submit_batch(batchsafeshutdown);
01642 }

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

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

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

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

char* ast_cdr_flags2str ( int  flag  ) 

Converts AMA flag to printable string

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

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

void ast_cdr_free ( struct ast_cdr cdr  ) 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing

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

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

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

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

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

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_disp2str(), ast_cdr_flags2str(), ast_cdr_getvar_internal(), ast_copy_string(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_cdr::billsec, cdr_get_tv(), ast_cdr::channel, ast_cdr::clid, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::linkedid, ast_cdr::peeraccount, ast_cdr::sequence, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

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

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

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

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

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

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
Returns:
0 by default

Definition at line 893 of file cdr.c.

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

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

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

int ast_cdr_isset_unanswered ( void   ) 

Definition at line 177 of file cdr.c.

References unanswered.

Referenced by ring_entry().

00178 {
00179    return unanswered;
00180 }

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

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

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

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

Referenced by ast_cdr_disposition(), and handle_cause().

00770 {
00771    char *chan;
00772 
00773    while (cdr) {
00774       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00775          chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
00776          check_post(cdr);
00777          cdr->disposition = AST_CDR_NOANSWER;
00778       }
00779       cdr = cdr->next;
00780    }
00781 }

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

Register a CDR handling engine.

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

Returns:
0 on success, -1 on failure

Definition at line 122 of file cdr.c.

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

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

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

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_flags::flags, ast_cdr::next, and ast_cdr::start.

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

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

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

Referenced by handle_showchan().

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

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

Set account code, will generate AMI event.

Definition at line 989 of file cdr.c.

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

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

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

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

Set AMA flags for channel.

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

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

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

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

Referenced by ast_bridge_call(), and dial_exec_full().

00831 {
00832 
00833    for (; cdr; cdr = cdr->next) {
00834       if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
00835          continue;
00836       if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00837          continue;
00838       check_post(cdr);
00839       cdr->answer = t;
00840    }
00841 }

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

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

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

00819 {
00820 
00821    for (; cdr; cdr = cdr->next) {
00822       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00823          check_post(cdr);
00824          ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp));
00825          ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata));
00826       }
00827    }
00828 }

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
Returns:
0 by default

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

00880 {
00881    for (; cdr; cdr = cdr->next) {
00882       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00883          set_one_cid(cdr, c);
00884    }
00885    return 0;
00886 }

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

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

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

00809 {
00810    for (; cdr; cdr = cdr->next) {
00811       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00812          check_post(cdr);
00813          ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
00814       }
00815    }
00816 }

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

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

Referenced by ast_bridge_call().

00844 {
00845 
00846    for (; cdr; cdr = cdr->next) {
00847       if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00848          continue;
00849       check_post(cdr);
00850       cdr->disposition = disposition;
00851    }
00852 }

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

Set the peer account.

Definition at line 1015 of file cdr.c.

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

Referenced by cdr_write().

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

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

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

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

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

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

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

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

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

void ast_cdr_specialized_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

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

Definition at line 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, ast_flags::flags, 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 717 of file cdr.c.

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

Referenced by __ast_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().

00718 {
00719    char *chan;
00720 
00721    for (; cdr; cdr = cdr->next) {
00722       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00723          chan = S_OR(cdr->channel, "<unknown>");
00724          check_post(cdr);
00725          cdr->start = ast_tvnow();
00726       }
00727    }
00728 }

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

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

int ast_cdr_update ( struct ast_channel chan  ) 

Update CDR on a channel

Definition at line 1082 of file cdr.c.

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

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

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

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

Definition at line 241 of file cdr.c.

References ast_localtime(), and ast_strftime().

Referenced by ast_cdr_getvar().

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

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

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

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

static int cdr_seq_inc ( struct ast_cdr cdr  )  [static]

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

00889 {
00890    return (cdr->sequence = ast_atomic_fetchadd_int(&cdr_sequence, +1));
00891 }

int check_cdr_enabled ( void   ) 

Return TRUE if CDR subsystem is enabled.

Definition at line 114 of file cdr.c.

References enabled.

Referenced by action_coresettings(), and handle_show_settings().

00115 {
00116    return enabled;
00117 }

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

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

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

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

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

static int do_reload ( int  reload  )  [static]

Definition at line 1484 of file cdr.c.

References ast_cdr_engine_term(), ast_cli_register(), ast_cli_unregister(), ast_cond_destroy, ast_cond_init, ast_config_destroy(), ast_config_load2(), ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN, AST_OPT_FLAG_INITIATED_SECONDS, ast_options, ast_pthread_create_background, AST_PTHREADT_NULL, ast_register_atexit(), ast_sched_add(), AST_SCHED_DEL, ast_set2_flag, ast_true(), ast_unregister_atexit(), ast_variable_retrieve(), BATCH_SAFE_SHUTDOWN_DEFAULT, BATCH_SCHEDULER_ONLY_DEFAULT, BATCH_SIZE_DEFAULT, BATCH_TIME_DEFAULT, batchmode, BATCHMODE_DEFAULT, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_batch_lock, cdr_pending_cond, cdr_sched, cdr_thread, cli_submit, config, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, do_cdr(), enabled, ENABLED_DEFAULT, EVENT_FLAG_SYSTEM, LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_event, submit_scheduled_batch(), unanswered, and UNANSWERED_DEFAULT.

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

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

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

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

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

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

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

01461 {
01462    switch (cmd) {
01463    case CLI_INIT:
01464       e->command = "cdr submit";
01465       e->usage =
01466          "Usage: cdr submit\n"
01467          "       Posts all pending batched CDR data to the configured CDR backend engine modules.\n";
01468       return NULL;
01469    case CLI_GENERATE:
01470       return NULL;
01471    }
01472    if (a->argc > 2)
01473       return CLI_SHOWUSAGE;
01474 
01475    submit_unscheduled_batch();
01476    ast_cli(a->fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
01477 
01478    return CLI_SUCCESS;
01479 }

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

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 1117 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, S_OR, and unanswered.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

01118 {
01119    char *chan;
01120    struct ast_cdr_beitem *i;
01121 
01122    for ( ; cdr ; cdr = cdr->next) {
01123       if (!unanswered && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
01124          /* For people, who don't want to see unanswered single-channel events */
01125          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01126          continue;
01127       }
01128 
01129       /* don't post CDRs that are for dialed channels unless those
01130        * channels were originated from asterisk (pbx_spool, manager,
01131        * cli) */
01132       if (ast_test_flag(cdr, AST_CDR_FLAG_DIALED) && !ast_test_flag(cdr, AST_CDR_FLAG_ORIGINATED)) {
01133          ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
01134          continue;
01135       }
01136 
01137       chan = S_OR(cdr->channel, "<unknown>");
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 855 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().

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

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

Definition at line 1301 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

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

static void submit_unscheduled_batch ( void   )  [static]

Definition at line 1310 of file cdr.c.

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

Referenced by ast_cdr_detach(), and handle_cli_submit().

01311 {
01312    /* this is okay since we are not being called from within the scheduler */
01313    AST_SCHED_DEL(sched, cdr_sched);
01314    /* schedule the submission to occur ASAP (1 ms) */
01315    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
01316    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
01317    ast_mutex_lock(&cdr_pending_lock);
01318    ast_cond_signal(&cdr_pending_cond);
01319    ast_mutex_unlock(&cdr_pending_lock);
01320 }


Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]

Definition at line 56 of file cdr.c.

Referenced by __ast_channel_alloc_ap().

int ast_default_amaflags = AST_CDR_DOCUMENTATION

Default AMA flag for billing records (CDR's)

Definition at line 55 of file cdr.c.

Referenced by __ast_channel_alloc_ap(), and ast_bridge_call().

struct ast_cdr_batch * batch [static]

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

const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1 [static]

Definition at line 106 of file cdr.c.

Referenced by do_reload().

const int BATCH_SCHEDULER_ONLY_DEFAULT = 0 [static]

Definition at line 103 of file cdr.c.

Referenced by do_reload().

const int BATCH_SIZE_DEFAULT = 100 [static]

Definition at line 97 of file cdr.c.

Referenced by do_reload().

const int BATCH_TIME_DEFAULT = 300 [static]

Definition at line 100 of file cdr.c.

Referenced by do_reload().

int batchmode [static]

Definition at line 90 of file cdr.c.

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

const int BATCHMODE_DEFAULT = 0 [static]

Definition at line 91 of file cdr.c.

Referenced by do_reload().

int batchsafeshutdown [static]

Definition at line 105 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 102 of file cdr.c.

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

int batchsize [static]

Definition at line 96 of file cdr.c.

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

int batchtime [static]

Definition at line 99 of file cdr.c.

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

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

Definition at line 108 of file cdr.c.

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

ast_cond_t cdr_pending_cond [static]

Definition at line 112 of file cdr.c.

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

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

Definition at line 111 of file cdr.c.

Referenced by do_cdr(), and submit_unscheduled_batch().

const char* const cdr_readonly_vars[] [static]

Initial value:

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

Definition at line 328 of file cdr.c.

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

int cdr_sched = -1 [static]

Definition at line 84 of file cdr.c.

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

int cdr_sequence = 0 [static]

Definition at line 79 of file cdr.c.

Referenced by cdr_seq_inc().

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 85 of file cdr.c.

Referenced by do_reload().

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

Definition at line 1482 of file cdr.c.

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

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

Definition at line 1481 of file cdr.c.

Referenced by do_reload().

int enabled [static]

Definition at line 87 of file cdr.c.

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

const int ENABLED_DEFAULT = 1 [static]

Definition at line 88 of file cdr.c.

Referenced by do_reload().

struct sched_context* sched [static]

Definition at line 83 of file cdr.c.

int unanswered [static]

Definition at line 93 of file cdr.c.

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

const int UNANSWERED_DEFAULT = 0 [static]

Definition at line 94 of file cdr.c.

Referenced by do_reload().


Generated on Mon Jun 27 16:51:03 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7