Mon Oct 8 12:39:12 2012

Asterisk developer's documentation


cdr.c File Reference

Call Detail Record API. More...

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

Go to the source code of this file.

Data Structures

struct  ast_cdr_batch
struct  ast_cdr_batch_item
struct  ast_cdr_beitem
struct  be_list

Functions

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

Variables

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


Detailed Description

Call Detail Record API.

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

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

Definition in file cdr.c.


Function Documentation

struct ast_cdr* ast_cdr_alloc ( void   ) 

Allocate a CDR record.

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

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

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

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

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

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

Definition at line 1215 of file cdr.c.

References ast_cdr::next.

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

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

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

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

Note:
The channel should be locked before calling.

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

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

int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

Definition at line 382 of file cdr.c.

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

Referenced by ast_bridge_call(), and ast_cdr_dup().

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

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

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

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

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

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

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

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

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

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

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

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

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_cdr_fork().

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

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

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_bridge_call(), and ast_cdr_reset().

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

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

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

int ast_cdr_engine_reload ( void   ) 

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

Definition at line 1642 of file cdr.c.

References do_reload().

01643 {
01644    return do_reload(1);
01645 }

void ast_cdr_engine_term ( void   ) 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1637 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by can_safely_quit(), and do_reload().

01638 {
01639    ast_cdr_submit_batch(batchsafeshutdown);
01640 }

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

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

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

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

void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

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

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

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

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

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

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

int ast_cdr_init ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

Parameters:
cdr Call Detail Record to use for channel
chan Channel to bind CDR with Initializes a CDR and associates it with a particular channel
Note:
The channel should be locked before calling.
Returns:
0 by default

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

00897 {
00898    for ( ; cdr ; cdr = cdr->next) {
00899       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
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 183 of file cdr.c.

References unanswered.

Referenced by ring_entry().

00184 {
00185    return unanswered;
00186 }

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

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

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

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

Referenced by ast_cdr_disposition(), and handle_cause().

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

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

Register a CDR handling engine.

Return values:
0 on success.
-1 on error

Definition at line 128 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 load_config(), load_module(), odbc_load_module(), and unload_module().

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

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

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

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

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

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

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

Set account code, will generate AMI event.

Note:
The channel should be locked before calling.

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

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 *  amaflags 
)

Set AMA flags for channel.

Note:
The channel should be locked before calling.

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

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

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

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

int ast_cdr_setcid ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

Parameters:
cdr Call Detail Record to use for channel
chan Channel to bind CDR with Initializes a CDR and associates it with a particular channel
Note:
The channel should be locked before calling.
Returns:
0 by default

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

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

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

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

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

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

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

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

Referenced by ast_bridge_call().

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

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

Set the peer account.

Note:
The channel should be locked before calling.

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

Note:
The channel should be locked before calling.

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

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

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

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

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

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

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

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

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

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

void ast_cdr_unregister ( const char *  name  ) 

Unregister a CDR handling engine.

unregister a CDR driver

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

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

int ast_cdr_update ( struct ast_channel chan  ) 

Update CDR on a channel.

Note:
The channel should be locked before calling.

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

References ast_localtime(), and ast_strftime().

Referenced by ast_cdr_getvar().

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

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

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

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

static int cdr_seq_inc ( struct ast_cdr cdr  )  [static]

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

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

int check_cdr_enabled ( void   ) 

Return TRUE if CDR subsystem is enabled.

Definition at line 118 of file cdr.c.

References enabled.

Referenced by action_coresettings(), and handle_show_settings().

00119 {
00120    return enabled;
00121 }

static void check_post ( struct ast_cdr cdr  )  [static]

print a warning if cdr already posted

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

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

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

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

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

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

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

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

static int do_reload ( int  reload  )  [static]

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

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

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

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

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

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

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

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

static int init_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

Definition at line 1241 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

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

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

Referenced by ast_cdr_detach(), and do_batch_backend_process().

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

static void reset_batch ( void   )  [static]

Note:
Don't call without cdr_batch_lock

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

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

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

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

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

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

Definition at line 1299 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

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

static void submit_unscheduled_batch ( void   )  [static]

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

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


Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]

Definition at line 60 of file cdr.c.

Referenced by __ast_channel_alloc_ap().

int ast_default_amaflags = AST_CDR_DOCUMENTATION

Default AMA flag for billing records (CDR's)

Definition at line 59 of file cdr.c.

Referenced by __ast_channel_alloc_ap(), and ast_bridge_call().

struct ast_cdr_batch * batch [static]

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

Referenced by do_reload().

const int BATCH_SCHEDULER_ONLY_DEFAULT = 0 [static]

Definition at line 107 of file cdr.c.

Referenced by do_reload().

const int BATCH_SIZE_DEFAULT = 100 [static]

Definition at line 101 of file cdr.c.

Referenced by do_reload().

const int BATCH_TIME_DEFAULT = 300 [static]

Definition at line 104 of file cdr.c.

Referenced by do_reload().

int batchmode [static]

Definition at line 94 of file cdr.c.

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

const int BATCHMODE_DEFAULT = 0 [static]

Definition at line 95 of file cdr.c.

Referenced by do_reload().

int batchsafeshutdown [static]

Definition at line 109 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 106 of file cdr.c.

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

int batchsize [static]

Definition at line 100 of file cdr.c.

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

int batchtime [static]

Definition at line 103 of file cdr.c.

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

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

Definition at line 112 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 116 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 115 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 334 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 88 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 83 of file cdr.c.

Referenced by cdr_seq_inc().

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 89 of file cdr.c.

Referenced by do_reload().

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

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

Referenced by do_reload().

int enabled [static]

Definition at line 91 of file cdr.c.

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

const int ENABLED_DEFAULT = 1 [static]

Definition at line 92 of file cdr.c.

Referenced by do_reload().

struct sched_context* sched [static]

Definition at line 87 of file cdr.c.

int unanswered [static]

Definition at line 97 of file cdr.c.

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

const int UNANSWERED_DEFAULT = 0 [static]

Definition at line 98 of file cdr.c.

Referenced by do_reload().


Generated on Mon Oct 8 12:39:12 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7