Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:02 2007

Asterisk developer's documentation :: Codename Pineapple


cdr.c File Reference


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.

#include "asterisk.h"
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/logger.h"
#include "asterisk/callerid.h"
#include "asterisk/causes.h"
#include "asterisk/options.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 dependency graph for cdr.c:

Go to the source code of this file.

Data Structures

struct  ast_cdr_batch
struct  ast_cdr_batch_item
struct  ast_cdr_beitem

Defines

#define BATCH_SAFE_SHUTDOWN_DEFAULT   1
#define BATCH_SCHEDULER_ONLY_DEFAULT   0
#define BATCH_SIZE_DEFAULT   100
#define BATCH_TIME_DEFAULT   300

Functions

ast_cdrast_cdr_alloc (void)
 Allocate a CDR record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).
int ast_cdr_amaflags2int (const char *flag)
void ast_cdr_answer (struct ast_cdr *cdr)
ast_cdrast_cdr_append (struct ast_cdr *cdr, struct ast_cdr *newcdr)
int ast_cdr_appenduserfield (struct ast_channel *chan, const char *userfield)
void ast_cdr_busy (struct ast_cdr *cdr)
int ast_cdr_copy_vars (struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
void ast_cdr_detach (struct ast_cdr *cdr)
char * ast_cdr_disp2str (int disposition)
int ast_cdr_disposition (struct ast_cdr *cdr, int cause)
ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).
void ast_cdr_end (struct ast_cdr *cdr)
int ast_cdr_engine_init (void)
int ast_cdr_engine_reload (void)
void ast_cdr_engine_term (void)
void ast_cdr_failed (struct ast_cdr *cdr)
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_register (const char *name, const char *desc, ast_cdrbe be)
void ast_cdr_reset (struct ast_cdr *cdr, struct ast_flags *_flags)
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)
int ast_cdr_setamaflags (struct ast_channel *chan, const char *flag)
void ast_cdr_setapp (struct ast_cdr *cdr, char *app, char *data)
int ast_cdr_setcid (struct ast_cdr *cdr, struct ast_channel *c)
void ast_cdr_setdestchan (struct ast_cdr *cdr, const char *chann)
int ast_cdr_setuserfield (struct ast_channel *chan, const char *userfield)
int ast_cdr_setvar (struct ast_cdr *cdr, const char *name, const char *value, int recur)
void ast_cdr_start (struct ast_cdr *cdr)
void ast_cdr_submit_batch (int shutdown)
void ast_cdr_unregister (const char *name)
int ast_cdr_update (struct ast_channel *c)
static AST_LIST_HEAD_STATIC (be_list, ast_cdr_beitem)
 AST_MUTEX_DEFINE_STATIC (cdr_pending_lock)
 AST_MUTEX_DEFINE_STATIC (cdr_batch_lock)
static void cdr_get_tv (struct timeval tv, const char *fmt, char *buf, int bufsize)
static void check_post (struct ast_cdr *cdr)
 print a warning if cdr already posted
static void check_start (struct ast_cdr *cdr)
 print a warning if cdr already started
static void * do_batch_backend_process (void *data)
static void * do_cdr (void *data)
static int do_reload (void)
static int handle_cli_status (int fd, int argc, char *argv[])
static int handle_cli_submit (int fd, int argc, char *argv[])
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 (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 int batchmode
static int batchsafeshutdown
static int batchscheduleronly
static int batchsize
static int batchtime
static ast_cond_t cdr_pending_cond
static const char * cdr_readonly_vars []
static int cdr_sched = -1
static pthread_t cdr_thread = AST_PTHREADT_NULL
static struct ast_cli_entry cli_status
static struct ast_cli_entry cli_submit
static int enabled
static struct sched_contextsched


Define Documentation

#define BATCH_SAFE_SHUTDOWN_DEFAULT   1
 

Definition at line 89 of file cdr.c.

Referenced by do_reload().

#define BATCH_SCHEDULER_ONLY_DEFAULT   0
 

Definition at line 88 of file cdr.c.

Referenced by do_reload().

#define BATCH_SIZE_DEFAULT   100
 

Definition at line 86 of file cdr.c.

Referenced by do_reload().

#define BATCH_TIME_DEFAULT   300
 

Definition at line 87 of file cdr.c.

Referenced by do_reload().


Function Documentation

struct ast_cdr* ast_cdr_alloc void   ) 
 

Allocate a CDR record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).

Definition at line 437 of file cdr.c.

References ast_calloc.

Referenced by __agent_start_monitoring(), __ast_pbx_run(), __ast_request_and_dial(), ast_cdr_dup(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten(), and start_monitor_exec().

00438 {
00439    return ast_calloc(1, sizeof(struct ast_cdr));
00440 }

int ast_cdr_amaflags2int const char *  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 707 of file cdr.c.

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

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

00708 {
00709    if (!strcasecmp(flag, "default"))
00710       return 0;
00711    if (!strcasecmp(flag, "omit"))
00712       return AST_CDR_OMIT;
00713    if (!strcasecmp(flag, "billing"))
00714       return AST_CDR_BILLING;
00715    if (!strcasecmp(flag, "documentation"))
00716       return AST_CDR_DOCUMENTATION;
00717    return -1;
00718 }

void ast_cdr_answer struct ast_cdr cdr  ) 
 

Parameters:
cdr the cdr you wish to associate with the call Starts all CDR stuff necessary for doing CDR when answering a call NULL argument is just fine.

Definition at line 456 of file cdr.c.

References ast_cdr::answer, AST_CDR_ANSWERED, check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by __ast_answer(), and __ast_read().

00457 {
00458 
00459    for (; cdr; cdr = cdr->next) {
00460       check_post(cdr);
00461       if (cdr->disposition < AST_CDR_ANSWERED)
00462          cdr->disposition = AST_CDR_ANSWERED;
00463       if (ast_tvzero(cdr->answer))
00464          cdr->answer = ast_tvnow();
00465    }
00466 }

struct ast_cdr* ast_cdr_append struct ast_cdr cdr,
struct ast_cdr newcdr
 

Definition at line 778 of file cdr.c.

References ast_cdr::next.

Referenced by attempt_transfer().

00779 {
00780    struct ast_cdr *ret;
00781 
00782    if (cdr) {
00783       ret = cdr;
00784 
00785       while (cdr->next)
00786          cdr = cdr->next;
00787       cdr->next = newcdr;
00788    } else {
00789       ret = newcdr;
00790    }
00791 
00792    return ret;
00793 }

int ast_cdr_appenduserfield struct ast_channel chan,
const char *  userfield
 

Definition at line 674 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, ast_channel::cdr, len, ast_cdr::next, and ast_cdr::userfield.

Referenced by ast_bridge_call().

00675 {
00676    struct ast_cdr *cdr = chan->cdr;
00677 
00678    for ( ; cdr ; cdr = cdr->next) {
00679       int len = strlen(cdr->userfield);
00680 
00681       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00682          ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
00683    }
00684 
00685    return 0;
00686 }

void ast_cdr_busy struct ast_cdr cdr  ) 
 

Parameters:
cdr the cdr you wish to associate with the call Returns nothing important

Definition at line 468 of file cdr.c.

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

Referenced by ast_cdr_disposition().

00469 {
00470 
00471    for (; cdr; cdr = cdr->next) {
00472       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00473          check_post(cdr);
00474          if (cdr->disposition < AST_CDR_BUSY)
00475             cdr->disposition = AST_CDR_BUSY;
00476       }
00477    }
00478 }

int ast_cdr_copy_vars struct ast_cdr to_cdr,
struct ast_cdr from_cdr
 

Definition at line 324 of file cdr.c.

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

Referenced by ast_cdr_dup().

00325 {
00326    struct ast_var_t *variables, *newvariable = NULL;
00327    struct varshead *headpa, *headpb;
00328    const char *var, *val;
00329    int x = 0;
00330 
00331    headpa = &from_cdr->varshead;
00332    headpb = &to_cdr->varshead;
00333 
00334    AST_LIST_TRAVERSE(headpa,variables,entries) {
00335       if (variables &&
00336           (var = ast_var_name(variables)) && (val = ast_var_value(variables)) &&
00337           !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
00338          newvariable = ast_var_assign(var, val);
00339          AST_LIST_INSERT_HEAD(headpb, newvariable, entries);
00340          x++;
00341       }
00342    }
00343 
00344    return x;
00345 }

void ast_cdr_detach struct ast_cdr cdr  ) 
 

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

References ast_calloc, AST_CDR_FLAG_POST_DISABLED, ast_cdr_free(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, batch, batchmode, batchsize, ast_cdr_batch_item::cdr, enabled, ast_cdr_batch::head, init_batch(), LOG_DEBUG, ast_cdr_batch_item::next, option_debug, post_cdr(), ast_cdr_batch::size, submit_unscheduled_batch(), and ast_cdr_batch::tail.

Referenced by ast_cdr_reset(), ast_hangup(), and ast_pbx_outgoing_cdr_failed().

00891 {
00892    struct ast_cdr_batch_item *newtail;
00893    int curr;
00894 
00895    /* maybe they disabled CDR stuff completely, so just drop it */
00896    if (!enabled) {
00897       if (option_debug)
00898          ast_log(LOG_DEBUG, "Dropping CDR !\n");
00899       ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
00900       ast_cdr_free(cdr);
00901       return;
00902    }
00903 
00904    /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
00905    if (!batchmode) {
00906       post_cdr(cdr);
00907       ast_cdr_free(cdr);
00908       return;
00909    }
00910 
00911    /* otherwise, each CDR gets put into a batch list (at the end) */
00912    if (option_debug)
00913       ast_log(LOG_DEBUG, "CDR detaching from this thread\n");
00914 
00915    /* we'll need a new tail for every CDR */
00916    if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
00917       post_cdr(cdr);
00918       ast_cdr_free(cdr);
00919       return;
00920    }
00921 
00922    /* don't traverse a whole list (just keep track of the tail) */
00923    ast_mutex_lock(&cdr_batch_lock);
00924    if (!batch)
00925       init_batch();
00926    if (!batch->head) {
00927       /* new batch is empty, so point the head at the new tail */
00928       batch->head = newtail;
00929    } else {
00930       /* already got a batch with something in it, so just append a new tail */
00931       batch->tail->next = newtail;
00932    }
00933    newtail->cdr = cdr;
00934    batch->tail = newtail;
00935    curr = batch->size++;
00936    ast_mutex_unlock(&cdr_batch_lock);
00937 
00938    /* if we have enough stuff to post, then do it */
00939    if (curr >= (batchsize - 1))
00940       submit_unscheduled_batch();
00941 }

char* ast_cdr_disp2str int  disposition  ) 
 

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

References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_FAILED, and AST_CDR_NOANSWER.

Referenced by ast_cdr_getvar().

00610 {
00611    switch (disposition) {
00612    case AST_CDR_NOANSWER:
00613       return "NO ANSWER";
00614    case AST_CDR_FAILED:
00615       return "FAILED";     
00616    case AST_CDR_BUSY:
00617       return "BUSY";    
00618    case AST_CDR_ANSWERED:
00619       return "ANSWERED";
00620    }
00621    return "UNKNOWN";
00622 }

int ast_cdr_disposition struct ast_cdr cdr,
int  cause
 

Parameters:
cdr the cdr you wish to associate with the call Returns nothing important
cause the AST_CAUSE_*

Definition at line 491 of file cdr.c.

References AST_CAUSE_BUSY, AST_CAUSE_FAILURE, AST_CAUSE_NORMAL, AST_CAUSE_NOTDEFINED, ast_cdr_busy(), ast_cdr_failed(), ast_log(), LOG_WARNING, and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), and ast_pbx_outgoing_exten().

00492 {
00493    int res = 0;
00494 
00495    for (; cdr; cdr = cdr->next) {
00496       switch (cause) {
00497       case AST_CAUSE_BUSY:
00498          ast_cdr_busy(cdr);
00499          break;
00500       case AST_CAUSE_FAILURE:
00501          ast_cdr_failed(cdr);
00502          break;
00503       case AST_CAUSE_NORMAL:
00504          break;
00505       case AST_CAUSE_NOTDEFINED:
00506          res = -1;
00507          break;
00508       default:
00509          res = -1;
00510          ast_log(LOG_WARNING, "Cause not handled\n");
00511       }
00512    }
00513    return res;
00514 }

struct ast_cdr* ast_cdr_dup struct ast_cdr cdr  ) 
 

Duplicate a record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 167 of file cdr.c.

References ast_cdr_alloc(), and ast_cdr_copy_vars().

Referenced by ast_cdr_reset().

00168 {
00169    struct ast_cdr *newcdr = ast_cdr_alloc();
00170 
00171    if (!newcdr)
00172       return NULL;
00173 
00174    memcpy(newcdr, cdr, sizeof(*newcdr));
00175    /* The varshead is unusable, volatile even, after the memcpy so we take care of that here */
00176    memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
00177    ast_cdr_copy_vars(newcdr, cdr);
00178    newcdr->next = NULL;
00179 
00180    return newcdr;
00181 }

void ast_cdr_end struct ast_cdr cdr  ) 
 

Parameters:
cdr the cdr you have associated the call with Registers the end of call time in the cdr structure. Returns nothing important

Definition at line 594 of file cdr.c.

References AST_CDR_FAILED, ast_log(), ast_cdr::channel, check_post(), ast_cdr::disposition, ast_cdr::end, LOG_WARNING, ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by __ast_read(), __ast_request_and_dial(), ast_cdr_reset(), ast_hangup(), and ast_pbx_outgoing_cdr_failed().

00595 {
00596    for ( ; cdr ; cdr = cdr->next) {
00597       check_post(cdr);
00598       if (ast_tvzero(cdr->end))
00599          cdr->end = ast_tvnow();
00600       if (ast_tvzero(cdr->start)) {
00601          ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
00602          cdr->disposition = AST_CDR_FAILED;
00603       } else
00604          cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
00605       cdr->billsec = ast_tvzero(cdr->answer) ? 0 : cdr->end.tv_sec - cdr->answer.tv_sec;
00606    }
00607 }

int ast_cdr_engine_init void   ) 
 

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

Definition at line 1141 of file cdr.c.

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

01142 {
01143    int res;
01144 
01145    sched = sched_context_create();
01146    if (!sched) {
01147       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
01148       return -1;
01149    }
01150 
01151    ast_cli_register(&cli_status);
01152 
01153    res = do_reload();
01154    if (res) {
01155       ast_mutex_lock(&cdr_batch_lock);
01156       res = init_batch();
01157       ast_mutex_unlock(&cdr_batch_lock);
01158    }
01159 
01160    return res;
01161 }

int ast_cdr_engine_reload void   ) 
 

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

Definition at line 1170 of file cdr.c.

References do_reload().

01171 {
01172    return do_reload();
01173 }

void ast_cdr_engine_term void   ) 
 

Submit any remaining CDRs and prepare for shutdown

Definition at line 1165 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

01166 {
01167    ast_cdr_submit_batch(batchsafeshutdown);
01168 }

void ast_cdr_failed struct ast_cdr cdr  ) 
 

Parameters:
cdr the cdr you wish to associate with the call Returns nothing important

Definition at line 480 of file cdr.c.

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

Referenced by __ast_request_and_dial(), ast_cdr_disposition(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), and ast_pbx_outgoing_exten().

00481 {
00482    for (; cdr; cdr = cdr->next) {
00483       check_post(cdr);
00484       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00485          if (cdr->disposition < AST_CDR_FAILED)
00486             cdr->disposition = AST_CDR_FAILED;
00487       }
00488    }
00489 }

char* ast_cdr_flags2str int  flag  ) 
 

Converts AMA flag to printable string

Definition at line 625 of file cdr.c.

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

Referenced by _sip_show_device(), _sip_show_peer(), ast_cdr_getvar(), and sip_show_user().

00626 {
00627    switch (flag) {
00628    case AST_CDR_OMIT:
00629       return "OMIT";
00630    case AST_CDR_BILLING:
00631       return "BILLING";
00632    case AST_CDR_DOCUMENTATION:
00633       return "DOCUMENTATION";
00634    }
00635    return "Unknown";
00636 }

void ast_cdr_free struct ast_cdr cdr  ) 
 

Free a CDR record.

Parameters:
cdr ast_cdr structure to free Returns nothing important

Definition at line 418 of file cdr.c.

References AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, ast_cdr_free_vars(), ast_log(), ast_test_flag, ast_cdr::channel, ast_cdr::end, free, LOG_NOTICE, ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

00419 {
00420 
00421    while (cdr) {
00422       struct ast_cdr *next = cdr->next;
00423       char *chan = S_OR(cdr->channel, "<unknown>");
00424       if (!ast_test_flag(cdr, AST_CDR_FLAG_POSTED) && !ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
00425          ast_log(LOG_NOTICE, "CDR on channel '%s' not posted\n", chan);
00426       if (ast_tvzero(cdr->end))
00427          ast_log(LOG_NOTICE, "CDR on channel '%s' lacks end\n", chan);
00428       if (ast_tvzero(cdr->start))
00429          ast_log(LOG_NOTICE, "CDR on channel '%s' lacks start\n", chan);
00430 
00431       ast_cdr_free_vars(cdr, 0);
00432       free(cdr);
00433       cdr = next;
00434    }
00435 }

void ast_cdr_free_vars struct ast_cdr cdr,
int  recur
 

Definition at line 392 of file cdr.c.

References AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_cdr_free().

00393 {
00394 
00395    /* clear variables */
00396    for (; cdr; cdr = recur ? cdr->next : NULL) {
00397       struct ast_var_t *vardata;
00398       struct varshead *headp = &cdr->varshead;
00399       while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
00400          ast_var_delete(vardata);
00401    }
00402 }

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 215 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_strlen_zero(), 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, fmt, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by ast_cdr_serialize_variables().

00216 {
00217    const char *fmt = "%Y-%m-%d %T";
00218    const char *varbuf;
00219 
00220    *ret = NULL;
00221    /* special vars (the ones from the struct ast_cdr when requested by name) 
00222       I'd almost say we should convert all the stringed vals to vars */
00223 
00224    if (!strcasecmp(name, "clid"))
00225       ast_copy_string(workspace, cdr->clid, workspacelen);
00226    else if (!strcasecmp(name, "src"))
00227       ast_copy_string(workspace, cdr->src, workspacelen);
00228    else if (!strcasecmp(name, "dst"))
00229       ast_copy_string(workspace, cdr->dst, workspacelen);
00230    else if (!strcasecmp(name, "dcontext"))
00231       ast_copy_string(workspace, cdr->dcontext, workspacelen);
00232    else if (!strcasecmp(name, "channel"))
00233       ast_copy_string(workspace, cdr->channel, workspacelen);
00234    else if (!strcasecmp(name, "dstchannel"))
00235       ast_copy_string(workspace, cdr->dstchannel, workspacelen);
00236    else if (!strcasecmp(name, "lastapp"))
00237       ast_copy_string(workspace, cdr->lastapp, workspacelen);
00238    else if (!strcasecmp(name, "lastdata"))
00239       ast_copy_string(workspace, cdr->lastdata, workspacelen);
00240    else if (!strcasecmp(name, "start"))
00241       cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
00242    else if (!strcasecmp(name, "answer"))
00243       cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
00244    else if (!strcasecmp(name, "end"))
00245       cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
00246    else if (!strcasecmp(name, "duration"))
00247       snprintf(workspace, workspacelen, "%ld", cdr->duration);
00248    else if (!strcasecmp(name, "billsec"))
00249       snprintf(workspace, workspacelen, "%ld", cdr->billsec);
00250    else if (!strcasecmp(name, "disposition")) {
00251       if (raw) {
00252          snprintf(workspace, workspacelen, "%ld", cdr->disposition);
00253       } else {
00254          ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
00255       }
00256    } else if (!strcasecmp(name, "amaflags")) {
00257       if (raw) {
00258          snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
00259       } else {
00260          ast_copy_string(workspace, ast_cdr_flags2str(cdr->amaflags), workspacelen);
00261       }
00262    } else if (!strcasecmp(name, "accountcode"))
00263       ast_copy_string(workspace, cdr->accountcode, workspacelen);
00264    else if (!strcasecmp(name, "uniqueid"))
00265       ast_copy_string(workspace, cdr->uniqueid, workspacelen);
00266    else if (!strcasecmp(name, "userfield"))
00267       ast_copy_string(workspace, cdr->userfield, workspacelen);
00268    else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
00269       ast_copy_string(workspace, varbuf, workspacelen);
00270    else
00271       workspace[0] = '\0';
00272 
00273    if (!ast_strlen_zero(workspace))
00274       *ret = workspace;
00275 }

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

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

00184 {
00185    if (ast_strlen_zero(name))
00186       return NULL;
00187 
00188    for (; cdr; cdr = recur ? cdr->next : NULL) {
00189       struct ast_var_t *variables;
00190       struct varshead *headp = &cdr->varshead;
00191       AST_LIST_TRAVERSE(headp, variables, entries) {
00192          if (!strcasecmp(name, ast_var_name(variables)))
00193             return ast_var_value(variables);
00194       }
00195    }
00196 
00197    return NULL;
00198 }

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 Return is negligible. (returns 0 by default)

Definition at line 569 of file cdr.c.

References ast_channel::_state, ast_cdr::accountcode, ast_cdr::amaflags, ast_channel::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_default_amaflags, ast_log(), AST_STATE_UP, ast_strlen_zero(), ast_test_flag, ast_cdr::channel, ast_channel::context, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_channel::exten, LOG_WARNING, ast_cdr::next, S_OR, set_one_cid(), and ast_cdr::uniqueid.

Referenced by __ast_pbx_run(), __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), and ast_pbx_outgoing_exten().

00570 {
00571    char *chan;
00572 
00573    for ( ; cdr ; cdr = cdr->next) {
00574       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00575          chan = S_OR(cdr->channel, "<unknown>");
00576          if (!ast_strlen_zero(cdr->channel)) 
00577             ast_log(LOG_WARNING, "CDR already initialized on '%s'\n", chan); 
00578          ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
00579          set_one_cid(cdr, c);
00580 
00581          cdr->disposition = (c->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
00582          cdr->amaflags = c->amaflags ? c->amaflags :  ast_default_amaflags;
00583          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00584          /* Destination information */
00585          ast_copy_string(cdr->dst, c->exten, sizeof(cdr->dst));
00586          ast_copy_string(cdr->dcontext, c->context, sizeof(cdr->dcontext));
00587          /* Unique call identifier */
00588          ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid));
00589       }
00590    }
00591    return 0;
00592 }

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

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

Returns:
0 on success, -1 on failure

Definition at line 108 of file cdr.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), LOG_WARNING, and ast_cdr_beitem::name.

00109 {
00110    struct ast_cdr_beitem *i;
00111 
00112    if (!name)
00113       return -1;
00114    if (!be) {
00115       ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
00116       return -1;
00117    }
00118 
00119    AST_LIST_LOCK(&be_list);
00120    AST_LIST_TRAVERSE(&be_list, i, list) {
00121       if (!strcasecmp(name, i->name))
00122          break;
00123    }
00124    AST_LIST_UNLOCK(&be_list);
00125 
00126    if (i) {
00127       ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
00128       return -1;
00129    }
00130 
00131    if (!(i = ast_calloc(1, sizeof(*i))))  
00132       return -1;
00133 
00134    i->be = be;
00135    ast_copy_string(i->name, name, sizeof(i->name));
00136    ast_copy_string(i->desc, desc, sizeof(i->desc));
00137 
00138    AST_LIST_LOCK(&be_list);
00139    AST_LIST_INSERT_HEAD(&be_list, i, list);
00140    AST_LIST_UNLOCK(&be_list);
00141 
00142    return 0;
00143 }

void ast_cdr_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 741 of file cdr.c.

References ast_cdr_detach(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POSTED, ast_copy_flags, AST_FLAGS_ALL, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call_thread(), and pbx_builtin_resetcdr().

00742 {
00743    struct ast_cdr *dup;
00744    struct ast_flags flags = { 0 };
00745 
00746    if (_flags)
00747       ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
00748 
00749    for ( ; cdr ; cdr = cdr->next) {
00750       /* Detach if post is requested */
00751       if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00752          if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
00753             ast_cdr_end(cdr);
00754             if ((dup = ast_cdr_dup(cdr))) {
00755                ast_cdr_detach(dup);
00756             }
00757             ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
00758          }
00759 
00760          /* clear variables */
00761          if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
00762             ast_cdr_free_vars(cdr, 0);
00763          }
00764 
00765          /* Reset to initial state */
00766          ast_clear_flag(cdr, AST_FLAGS_ALL); 
00767          memset(&cdr->start, 0, sizeof(cdr->start));
00768          memset(&cdr->end, 0, sizeof(cdr->end));
00769          memset(&cdr->answer, 0, sizeof(cdr->answer));
00770          cdr->billsec = 0;
00771          cdr->duration = 0;
00772          ast_cdr_start(cdr);
00773          cdr->disposition = AST_CDR_NOANSWER;
00774       }
00775    }
00776 }

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

Definition at line 347 of file cdr.c.

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

Referenced by handle_showchan().

00348 {
00349    struct ast_var_t *variables;
00350    const char *var, *val;
00351    char *tmp;
00352    char workspace[256];
00353    int total = 0, x = 0, i;
00354 
00355    (*buf)->used = 0;
00356    (*buf)->str[0] = '\0';
00357 
00358    for (; cdr; cdr = recur ? cdr->next : NULL) {
00359       if (++x > 1)
00360          ast_str_append(buf, 0, "\n");
00361 
00362       AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
00363          if (variables &&
00364              (var = ast_var_name(variables)) && (val = ast_var_value(variables)) &&
00365              !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
00366             if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, val, sep) < 0) {
00367                ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
00368                break;
00369             } else
00370                total++;
00371          } else 
00372             break;
00373       }
00374 
00375       for (i = 0; cdr_readonly_vars[i]; i++) {
00376          ast_cdr_getvar(cdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
00377          if (!tmp)
00378             continue;
00379          
00380          if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, tmp, sep) < 0) {
00381             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
00382             break;
00383          } else
00384             total++;
00385       }
00386    }
00387 
00388    return total;
00389 }

int ast_cdr_setaccount struct ast_channel chan,
const char *  account
 

Definition at line 638 of file cdr.c.

References accountcode, ast_cdr::accountcode, AST_CDR_FLAG_LOCKED, ast_string_field_set, ast_test_flag, ast_channel::cdr, and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), and ast_pbx_outgoing_exten().

00639 {
00640    struct ast_cdr *cdr = chan->cdr;
00641 
00642    ast_string_field_set(chan, accountcode, account);
00643    for ( ; cdr ; cdr = cdr->next) {
00644       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00645          ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode));
00646    }
00647    return 0;
00648 }

int ast_cdr_setamaflags struct ast_channel chan,
const char *  flag
 

Definition at line 650 of file cdr.c.

References ast_cdr::amaflags, ast_cdr_amaflags2int(), ast_channel::cdr, and ast_cdr::next.

Referenced by pbx_builtin_setamaflags().

00651 {
00652    struct ast_cdr *cdr;
00653    int newflag = ast_cdr_amaflags2int(flag);
00654    if (newflag) {
00655       for (cdr = chan->cdr; cdr; cdr = cdr->next)
00656          cdr->amaflags = newflag;
00657    }
00658 
00659    return 0;
00660 }

void ast_cdr_setapp struct ast_cdr cdr,
char *  app,
char *  data
 

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

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

Referenced by __ast_request_and_dial(), and pbx_exec().

00526 {
00527 
00528    for (; cdr; cdr = cdr->next) {
00529       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00530          check_post(cdr);
00531          if (!app)
00532             app = "";
00533          ast_copy_string(cdr->lastapp, app, sizeof(cdr->lastapp));
00534          if (!data)
00535             data = "";
00536          ast_copy_string(cdr->lastdata, data, sizeof(cdr->lastdata));
00537       }
00538    }
00539 }

int ast_cdr_setcid struct ast_cdr cdr,
struct ast_channel chan
 

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 Return is negligible. (returns 0 by default)

Definition at line 560 of file cdr.c.

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

Referenced by ast_set_callerid().

00561 {
00562    for (; cdr; cdr = cdr->next) {
00563       if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00564          set_one_cid(cdr, c);
00565    }
00566    return 0;
00567 }

void ast_cdr_setdestchan struct ast_cdr cdr,
const char *  chan
 

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

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

Referenced by ast_bridge_call_thread(), and park_exec().

00517 {
00518    for (; cdr; cdr = cdr->next) {
00519       check_post(cdr);
00520       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
00521          ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
00522    }
00523 }

int ast_cdr_setuserfield struct ast_channel chan,
const char *  userfield
 

Definition at line 662 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, ast_channel::cdr, ast_cdr::next, and ast_cdr::userfield.

Referenced by __agent_start_monitoring(), ast_bridge_call(), handle_request_info(), and start_monitor_exec().

00663 {
00664    struct ast_cdr *cdr = chan->cdr;
00665 
00666    for ( ; cdr ; cdr = cdr->next) {
00667       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 
00668          ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
00669    }
00670 
00671    return 0;
00672 }

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

References ast_log(), and LOG_ERROR.

00286 {
00287    struct ast_var_t *newvariable;
00288    struct varshead *headp;
00289    int x;
00290    
00291    for (x = 0; cdr_readonly_vars[x]; x++) {
00292       if (!strcasecmp(name, cdr_readonly_vars[x])) {
00293          ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!.\n", name);
00294          return -1;
00295       }
00296    }
00297 
00298    if (!cdr) {
00299       ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n");
00300       return -1;
00301    }
00302 
00303    for (; cdr; cdr = recur ? cdr->next : NULL) {
00304       headp = &cdr->varshead;
00305       AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
00306          if (!strcasecmp(ast_var_name(newvariable), name)) {
00307             /* there is already such a variable, delete it */
00308             AST_LIST_REMOVE_CURRENT(headp, entries);
00309             ast_var_delete(newvariable);
00310             break;
00311          }
00312       }
00313       AST_LIST_TRAVERSE_SAFE_END;
00314 
00315       if (value) {
00316          newvariable = ast_var_assign(name, value);
00317          AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00318       }
00319    }
00320 
00321    return 0;
00322 }

void ast_cdr_start struct ast_cdr cdr  ) 
 

Parameters:
cdr the cdr you wish to associate with the call Starts all CDR stuff necessary for monitoring a call Returns nothing important

Definition at line 442 of file cdr.c.

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

Referenced by __ast_pbx_run(), __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), and ast_pbx_outgoing_exten().

00443 {
00444    char *chan; 
00445 
00446    for (; cdr; cdr = cdr->next) {
00447       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00448          chan = S_OR(cdr->channel, "<unknown>");
00449          check_post(cdr);
00450          check_start(cdr);
00451          cdr->start = ast_tvnow();
00452       }
00453    }
00454 }

void ast_cdr_submit_batch int  shutdown  ) 
 

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

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, batch, batchscheduleronly, do_batch_backend_process(), ast_cdr_batch::head, LOG_DEBUG, LOG_WARNING, option_debug, and reset_batch().

Referenced by ast_cdr_engine_term(), and submit_scheduled_batch().

00833 {
00834    struct ast_cdr_batch_item *oldbatchitems = NULL;
00835    pthread_attr_t attr;
00836    pthread_t batch_post_thread = AST_PTHREADT_NULL;
00837 
00838    /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
00839    if (!batch || !batch->head)
00840       return;
00841 
00842    /* move the old CDRs aside, and prepare a new CDR batch */
00843    ast_mutex_lock(&cdr_batch_lock);
00844    oldbatchitems = batch->head;
00845    reset_batch();
00846    ast_mutex_unlock(&cdr_batch_lock);
00847 
00848    /* if configured, spawn a new thread to post these CDRs,
00849       also try to save as much as possible if we are shutting down safely */
00850    if (batchscheduleronly || shutdown) {
00851       if (option_debug)
00852          ast_log(LOG_DEBUG, "CDR single-threaded batch processing begins now\n");
00853       do_batch_backend_process(oldbatchitems);
00854    } else {
00855       pthread_attr_init(&attr);
00856       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00857       if (ast_pthread_create_background(&batch_post_thread, &attr, do_batch_backend_process, oldbatchitems)) {
00858          ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
00859          do_batch_backend_process(oldbatchitems);
00860       } else {
00861          if (option_debug)
00862             ast_log(LOG_DEBUG, "CDR multi-threaded batch processing begins now\n");
00863       }
00864       pthread_attr_destroy(&attr);
00865    }
00866 }

void ast_cdr_unregister const char *  name  ) 
 

unregister a CDR driver

Definition at line 146 of file cdr.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_verbose(), free, ast_cdr_beitem::name, option_verbose, and VERBOSE_PREFIX_2.

00147 {
00148    struct ast_cdr_beitem *i = NULL;
00149 
00150    AST_LIST_LOCK(&be_list);
00151    AST_LIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
00152       if (!strcasecmp(name, i->name)) {
00153          AST_LIST_REMOVE_CURRENT(&be_list, list);
00154          if (option_verbose > 1)
00155             ast_verbose(VERBOSE_PREFIX_2 "Unregistered '%s' CDR backend\n", name);
00156          free(i);
00157          break;
00158       }
00159    }
00160    AST_LIST_TRAVERSE_SAFE_END;
00161    AST_LIST_UNLOCK(&be_list);
00162 }

int ast_cdr_update struct ast_channel c  ) 
 

Definition at line 688 of file cdr.c.

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

Referenced by __ast_request_and_dial(), ast_parseable_goto(), and cb_events().

00689 {
00690    struct ast_cdr *cdr = c->cdr;
00691 
00692    for ( ; cdr ; cdr = cdr->next) {
00693       if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
00694          set_one_cid(cdr, c);
00695 
00696          /* Copy account code et-al */ 
00697          ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
00698          /* Destination information */ /* XXX privilege macro* ? */
00699          ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst));
00700          ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext));
00701       }
00702    }
00703 
00704    return 0;
00705 }

static AST_LIST_HEAD_STATIC be_list  ,
ast_cdr_beitem 
[static]
 

AST_MUTEX_DEFINE_STATIC cdr_pending_lock   ) 
 

AST_MUTEX_DEFINE_STATIC cdr_batch_lock   ) 
 

static void cdr_get_tv struct timeval  tv,
const char *  fmt,
char *  buf,
int  bufsize
[static]
 

Definition at line 200 of file cdr.c.

Referenced by ast_cdr_getvar().

00201 {
00202    if (fmt == NULL) {   /* raw mode */
00203       snprintf(buf, bufsize, "%ld.%06ld", (long)tv.tv_sec, (long)tv.tv_usec);
00204    } else {  
00205       time_t t = tv.tv_sec;
00206       if (t) {
00207          struct tm tm;
00208          localtime_r(&t, &tm);
00209          strftime(buf, bufsize, fmt, &tm);
00210       }
00211    }
00212 }

static void check_post struct ast_cdr cdr  )  [static]
 

print a warning if cdr already posted

Definition at line 405 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_setapp(), ast_cdr_setdestchan(), ast_cdr_start(), and post_cdr().

00406 {
00407    if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
00408       ast_log(LOG_NOTICE, "CDR on channel '%s' already posted\n", S_OR(cdr->channel, "<unknown>"));
00409 }

static void check_start struct ast_cdr cdr  )  [static]
 

print a warning if cdr already started

Definition at line 412 of file cdr.c.

References ast_log(), ast_cdr::channel, LOG_NOTICE, S_OR, and ast_cdr::start.

Referenced by ast_cdr_start().

00413 {
00414    if (!ast_tvzero(cdr->start))
00415       ast_log(LOG_NOTICE, "CDR on channel '%s' already started\n", S_OR(cdr->channel, "<unknown>"));
00416 }

static void* do_batch_backend_process void *  data  )  [static]
 

Definition at line 815 of file cdr.c.

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

Referenced by ast_cdr_submit_batch().

00816 {
00817    struct ast_cdr_batch_item *processeditem;
00818    struct ast_cdr_batch_item *batchitem = data;
00819 
00820    /* Push each CDR into storage mechanism(s) and free all the memory */
00821    while (batchitem) {
00822       post_cdr(batchitem->cdr);
00823       ast_cdr_free(batchitem->cdr);
00824       processeditem = batchitem;
00825       batchitem = batchitem->next;
00826       free(processeditem);
00827    }
00828 
00829    return NULL;
00830 }

static void* do_cdr void *  data  )  [static]
 

Definition at line 943 of file cdr.c.

References ast_cond_timedwait(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_runq(), ast_sched_wait(), ast_tvadd(), cdr_pending_cond, LOG_DEBUG, and option_debug.

Referenced by do_reload().

00944 {
00945    struct timespec timeout;
00946    int schedms;
00947    int numevents = 0;
00948 
00949    for (;;) {
00950       struct timeval now;
00951       schedms = ast_sched_wait(sched);
00952       /* this shouldn't happen, but provide a 1 second default just in case */
00953       if (schedms <= 0)
00954          schedms = 1000;
00955       now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
00956       timeout.tv_sec = now.tv_sec;
00957       timeout.tv_nsec = now.tv_usec * 1000;
00958       /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
00959       ast_mutex_lock(&cdr_pending_lock);
00960       ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
00961       numevents = ast_sched_runq(sched);
00962       ast_mutex_unlock(&cdr_pending_lock);
00963       if (option_debug > 1)
00964          ast_log(LOG_DEBUG, "Processed %d scheduled CDR batches from the run queue\n", numevents);
00965    }
00966 
00967    return NULL;
00968 }

static int do_reload void   )  [static]
 

Definition at line 1029 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_load(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN, 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, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_pending_cond, cdr_sched, cdr_thread, cli_submit, config, do_cdr(), enabled, LOG_ERROR, LOG_NOTICE, LOG_WARNING, and submit_scheduled_batch().

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

01030 {
01031    struct ast_config *config;
01032    const char *enabled_value;
01033    const char *batched_value;
01034    const char *scheduleronly_value;
01035    const char *batchsafeshutdown_value;
01036    const char *size_value;
01037    const char *time_value;
01038    const char *end_before_h_value;
01039    int cfg_size;
01040    int cfg_time;
01041    int was_enabled;
01042    int was_batchmode;
01043    int res=0;
01044 
01045    ast_mutex_lock(&cdr_batch_lock);
01046 
01047    batchsize = BATCH_SIZE_DEFAULT;
01048    batchtime = BATCH_TIME_DEFAULT;
01049    batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
01050    batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
01051    was_enabled = enabled;
01052    was_batchmode = batchmode;
01053    enabled = 1;
01054    batchmode = 0;
01055 
01056    /* don't run the next scheduled CDR posting while reloading */
01057    if (cdr_sched > -1)
01058       ast_sched_del(sched, cdr_sched);
01059 
01060    if ((config = ast_config_load("cdr.conf"))) {
01061       if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
01062          enabled = ast_true(enabled_value);
01063       }
01064       if ((batched_value = ast_variable_retrieve(config, "general", "batch"))) {
01065          batchmode = ast_true(batched_value);
01066       }
01067       if ((scheduleronly_value = ast_variable_retrieve(config, "general", "scheduleronly"))) {
01068          batchscheduleronly = ast_true(scheduleronly_value);
01069       }
01070       if ((batchsafeshutdown_value = ast_variable_retrieve(config, "general", "safeshutdown"))) {
01071          batchsafeshutdown = ast_true(batchsafeshutdown_value);
01072       }
01073       if ((size_value = ast_variable_retrieve(config, "general", "size"))) {
01074          if (sscanf(size_value, "%d", &cfg_size) < 1)
01075             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", size_value);
01076          else if (size_value < 0)
01077             ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
01078          else
01079             batchsize = cfg_size;
01080       }
01081       if ((time_value = ast_variable_retrieve(config, "general", "time"))) {
01082          if (sscanf(time_value, "%d", &cfg_time) < 1)
01083             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", time_value);
01084          else if (time_value < 0)
01085             ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
01086          else
01087             batchtime = cfg_time;
01088       }
01089       if ((end_before_h_value = ast_variable_retrieve(config, "general", "endbeforehexten")))
01090          ast_set2_flag(&ast_options, ast_true(end_before_h_value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
01091    }
01092 
01093    if (enabled && !batchmode) {
01094       ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
01095    } else if (enabled && batchmode) {
01096       cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
01097       ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
01098    } else {
01099       ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
01100    }
01101 
01102    /* if this reload enabled the CDR batch mode, create the background thread
01103       if it does not exist */
01104    if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
01105       ast_cond_init(&cdr_pending_cond, NULL);
01106       if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
01107          ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
01108          ast_sched_del(sched, cdr_sched);
01109       } else {
01110          ast_cli_register(&cli_submit);
01111          ast_register_atexit(ast_cdr_engine_term);
01112          res = 0;
01113       }
01114    /* if this reload disabled the CDR and/or batch mode and there is a background thread,
01115       kill it */
01116    } else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
01117       /* wake up the thread so it will exit */
01118       pthread_cancel(cdr_thread);
01119       pthread_kill(cdr_thread, SIGURG);
01120       pthread_join(cdr_thread, NULL);
01121       cdr_thread = AST_PTHREADT_NULL;
01122       ast_cond_destroy(&cdr_pending_cond);
01123       ast_cli_unregister(&cli_submit);
01124       ast_unregister_atexit(ast_cdr_engine_term);
01125       res = 0;
01126       /* if leaving batch mode, then post the CDRs in the batch,
01127          and don't reschedule, since we are stopping CDR logging */
01128       if (!batchmode && was_batchmode) {
01129          ast_cdr_engine_term();
01130       }
01131    } else {
01132       res = 0;
01133    }
01134 
01135    ast_mutex_unlock(&cdr_batch_lock);
01136    ast_config_destroy(config);
01137 
01138    return res;
01139 }

static int handle_cli_status int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 970 of file cdr.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_sched_when(), batch, batchmode, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_sched, enabled, ESS, ast_cdr_beitem::name, and RESULT_SHOWUSAGE.

00971 {
00972    struct ast_cdr_beitem *beitem=NULL;
00973    int cnt=0;
00974    long nextbatchtime=0;
00975 
00976    if (argc > 2)
00977       return RESULT_SHOWUSAGE;
00978 
00979    ast_cli(fd, "CDR logging: %s\n", enabled ? "enabled" : "disabled");
00980    ast_cli(fd, "CDR mode: %s\n", batchmode ? "batch" : "simple");
00981    if (enabled) {
00982       if (batchmode) {
00983          if (batch)
00984             cnt = batch->size;
00985          if (cdr_sched > -1)
00986             nextbatchtime = ast_sched_when(sched, cdr_sched);
00987          ast_cli(fd, "CDR safe shut down: %s\n", batchsafeshutdown ? "enabled" : "disabled");
00988          ast_cli(fd, "CDR batch threading model: %s\n", batchscheduleronly ? "scheduler only" : "scheduler plus separate threads");
00989          ast_cli(fd, "CDR current batch size: %d record%s\n", cnt, ESS(cnt));
00990          ast_cli(fd, "CDR maximum batch size: %d record%s\n", batchsize, ESS(batchsize));
00991          ast_cli(fd, "CDR maximum batch time: %d second%s\n", batchtime, ESS(batchtime));
00992          ast_cli(fd, "CDR next scheduled batch processing time: %ld second%s\n", nextbatchtime, ESS(nextbatchtime));
00993       }
00994       AST_LIST_LOCK(&be_list);
00995       AST_LIST_TRAVERSE(&be_list, beitem, list) {
00996          ast_cli(fd, "CDR registered backend: %s\n", beitem->name);
00997       }
00998       AST_LIST_UNLOCK(&be_list);
00999    }
01000 
01001    return 0;
01002 }

static int handle_cli_submit int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 1004 of file cdr.c.

References ast_cli(), RESULT_SHOWUSAGE, and submit_unscheduled_batch().

01005 {
01006    if (argc > 2)
01007       return RESULT_SHOWUSAGE;
01008 
01009    submit_unscheduled_batch();
01010    ast_cli(fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
01011 
01012    return 0;
01013 }

static int init_batch void   )  [static]
 

Note:
Don't call without cdr_batch_lock

Definition at line 804 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach(), and ast_cdr_engine_init().

00805 {
00806    /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
00807    if (!(batch = ast_malloc(sizeof(*batch))))
00808       return -1;
00809 
00810    reset_batch();
00811 
00812    return 0;
00813 }

static void post_cdr struct ast_cdr cdr  )  [static]
 

Definition at line 720 of file cdr.c.

References AST_CDR_FLAG_POSTED, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_set_flag, ast_cdr_beitem::be, ast_cdr::channel, check_post(), ast_cdr::end, LOG_WARNING, ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

00721 {
00722    char *chan;
00723    struct ast_cdr_beitem *i;
00724 
00725    for ( ; cdr ; cdr = cdr->next) {
00726       chan = S_OR(cdr->channel, "<unknown>");
00727       check_post(cdr);
00728       if (ast_tvzero(cdr->end))
00729          ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan);
00730       if (ast_tvzero(cdr->start))
00731          ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
00732       ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
00733       AST_LIST_LOCK(&be_list);
00734       AST_LIST_TRAVERSE(&be_list, i, list) {
00735          i->be(cdr);
00736       }
00737       AST_LIST_UNLOCK(&be_list);
00738    }
00739 }

static void reset_batch void   )  [static]
 

Note:
Don't call without cdr_batch_lock

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

00797 {
00798    batch->size = 0;
00799    batch->head = NULL;
00800    batch->tail = NULL;
00801 }

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

Definition at line 542 of file cdr.c.

References ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_cdr::clid, S_OR, and ast_cdr::src.

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

00543 {
00544    /* Grab source from ANI or normal Caller*ID */
00545    const char *num = S_OR(c->cid.cid_ani, c->cid.cid_num);
00546    
00547    if (!ast_strlen_zero(c->cid.cid_name)) {
00548       if (!ast_strlen_zero(num)) /* both name and number */
00549          snprintf(cdr->clid, sizeof(cdr->clid), "\"%s\" <%s>", c->cid.cid_name, num);
00550       else           /* only name */
00551          ast_copy_string(cdr->clid, c->cid.cid_name, sizeof(cdr->clid));
00552    } else if (!ast_strlen_zero(num)) { /* only number */
00553       ast_copy_string(cdr->clid, num, sizeof(cdr->clid));
00554    } else {          /* nothing known */
00555       cdr->clid[0] = '\0';
00556    }
00557    ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src));
00558 
00559 }

static int submit_scheduled_batch void *  data  )  [static]
 

Definition at line 868 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

00869 {
00870    ast_cdr_submit_batch(0);
00871    /* manually reschedule from this point in time */
00872    cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
00873    /* returning zero so the scheduler does not automatically reschedule */
00874    return 0;
00875 }

static void submit_unscheduled_batch void   )  [static]
 

Definition at line 877 of file cdr.c.

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

Referenced by ast_cdr_detach(), and handle_cli_submit().

00878 {
00879    /* this is okay since we are not being called from within the scheduler */
00880    if (cdr_sched > -1)
00881       ast_sched_del(sched, cdr_sched);
00882    /* schedule the submission to occur ASAP (1 ms) */
00883    cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
00884    /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
00885    ast_mutex_lock(&cdr_pending_lock);
00886    ast_cond_signal(&cdr_pending_cond);
00887    ast_mutex_unlock(&cdr_pending_lock);
00888 }


Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]
 

Definition at line 60 of file cdr.c.

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

struct ast_cdr_batch * batch [static]
 

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

int batchmode [static]
 

Definition at line 92 of file cdr.c.

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

int batchsafeshutdown [static]
 

Definition at line 96 of file cdr.c.

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

int batchscheduleronly [static]
 

Definition at line 95 of file cdr.c.

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

int batchsize [static]
 

Definition at line 93 of file cdr.c.

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

int batchtime [static]
 

Definition at line 94 of file cdr.c.

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

ast_cond_t cdr_pending_cond [static]
 

Definition at line 102 of file cdr.c.

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

const char* cdr_readonly_vars[] [static]
 

Initial value:

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

Definition at line 278 of file cdr.c.

Referenced by ast_cdr_serialize_variables().

int cdr_sched = -1 [static]
 

Definition at line 83 of file cdr.c.

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

pthread_t cdr_thread = AST_PTHREADT_NULL [static]
 

Definition at line 84 of file cdr.c.

Referenced by do_reload().

struct ast_cli_entry cli_status [static]
 

Definition at line 1022 of file cdr.c.

Referenced by ast_cdr_engine_init(), and dnsmgr_init().

struct ast_cli_entry cli_submit [static]
 

Definition at line 1015 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(), ast_dnsmgr_lookup(), do_reload(), handle_cli_status(), init_manager(), load_odbc_config(), and reload().

struct sched_context* sched [static]
 

Definition at line 82 of file cdr.c.

Referenced by __attempt_transmit(), __iax2_poke_noanswer(), __oh323_destroy(), __oh323_rtp_create(), __oh323_update_info(), __send_lagrq(), __send_ping(), __sip_ack(), __sip_destroy(), __sip_reliable_xmit(), __sip_semi_ack(), __unload_module(), _sip_show_peer(), ack_trans(), ast_rtp_new(), ast_rtp_new_with_bindaddr(), ast_udptl_new(), auth_fail(), build_peer(), delete_users(), destroy_packet(), destroy_packets(), destroy_peer(), dnsmgr_init(), dnsmgr_start_refresh(), do_refresh(), do_register(), do_reload(), dundi_discover(), dundi_query(), dundi_send(), handle_command_response(), handle_response_invite(), handle_response_peerpoke(), handle_response_register(), iax2_ack_registry(), iax2_call(), iax2_destroy_helper(), iax2_do_register(), iax2_dprequest(), iax2_frame_free(), iax2_poke_peer(), iax2_provision(), load_module(), make_trunk(), network_thread(), parse_register_contact(), populate_addr(), qualify_peer(), reg_source_db(), sched_thread(), schedule_delivery(), sip_alloc(), sip_call(), sip_cancel_destroy(), sip_destroy_peer(), sip_poke_all_peers(), sip_poke_noanswer(), sip_poke_peer(), sip_registry_destroy(), sip_scheddestroy(), sip_send_all_registers(), socket_process(), transmit_register(), unload_module(), update_jbsched(), and update_registry().


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen