Sat Apr 26 2014 22:02:00

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"
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
struct  be_list

Functions

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

Variables

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

Detailed Description

Call Detail Record API.

Author:
Mark Spencer <markster@digium.com>
Note:
Includes code and algorithms from the Zapata library.
We do a lot of checking here in the CDR code to try to be sure we don't ever let a CDR slip through our fingers somehow. If someone allocates a CDR, it must be completely handled normally or a WARNING shall be logged, so that we can best keep track of any escape condition where the CDR isn't properly generated and posted.

Definition in file cdr.c.


Function Documentation

struct ast_cdr* ast_cdr_alloc ( void  ) [read]

Allocate a CDR record.

Return values:
amalloc'd ast_cdr structure
NULLon error (malloc failure)

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

{
   struct ast_cdr *x;
   x = ast_calloc(1, sizeof(*x));
   if (!x)
      ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
   return x;
}
int ast_cdr_amaflags2int ( const char *  flag)

Convert a string to a detail record AMA flag.

Parameters:
flagstring form of flag Converts the string form of the flag to the binary form.
Returns:
the binary form of the flag

Definition at line 1154 of file cdr.c.

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

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

{
   if (!strcasecmp(flag, "default"))
      return 0;
   if (!strcasecmp(flag, "omit"))
      return AST_CDR_OMIT;
   if (!strcasecmp(flag, "billing"))
      return AST_CDR_BILLING;
   if (!strcasecmp(flag, "documentation"))
      return AST_CDR_DOCUMENTATION;
   return -1;
}
void ast_cdr_answer ( struct ast_cdr cdr)

Answer a call.

Parameters:
cdrthe 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 748 of file cdr.c.

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

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

{

   for (; cdr; cdr = cdr->next) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
         continue;
      if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      check_post(cdr);
      if (cdr->disposition < AST_CDR_ANSWERED)
         cdr->disposition = AST_CDR_ANSWERED;
      if (ast_tvzero(cdr->answer))
         cdr->answer = ast_tvnow();
   }
}
struct ast_cdr* ast_cdr_append ( struct ast_cdr cdr,
struct ast_cdr newcdr 
) [read]

Definition at line 1265 of file cdr.c.

References ast_cdr::next.

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

{
   struct ast_cdr *ret;

   if (cdr) {
      ret = cdr;

      while (cdr->next)
         cdr = cdr->next;
      cdr->next = newcdr;
   } else {
      ret = newcdr;
   }

   return ret;
}
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 1118 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_channel_cdr(), ast_copy_string(), ast_test_flag, len(), ast_cdr::next, and ast_cdr::userfield.

Referenced by ast_bridge_call().

{
   struct ast_cdr *cdr = ast_channel_cdr(chan);

   for ( ; cdr ; cdr = cdr->next) {
      int len = strlen(cdr->userfield);

      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
   }

   return 0;
}
void ast_cdr_busy ( struct ast_cdr cdr)

Busy a call.

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

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

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

{

   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         cdr->disposition = AST_CDR_BUSY;
      }
   }
}
void ast_cdr_congestion ( struct ast_cdr cdr)

A call was set to congestion.

Parameters:
cdrthe cdr you wish to associate with the call Markst he channel disposition as "CONGESTION" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application

Definition at line 798 of file cdr.c.

References AST_CDR_CONGESTION, ast_cdr_failed(), AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POSTED, ast_log(), ast_strlen_zero(), ast_test_flag, ast_cdr::channel, congestion, ast_cdr::disposition, LOG_WARNING, and ast_cdr::next.

Referenced by ast_cdr_disposition(), and pbx_builtin_congestion().

{
   char *chan;

   /* if congestion log is disabled, pass the buck to ast_cdr_failed */
   if (!congestion) {
      ast_cdr_failed(cdr);
   }

   while (cdr && congestion) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";

         if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED)) {
            ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
         }

         if (cdr->disposition < AST_CDR_CONGESTION) {
            cdr->disposition = AST_CDR_CONGESTION;
         }
      }
      cdr = cdr->next;
   }
}
int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

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

{
   struct ast_var_t *variables, *newvariable = NULL;
   struct varshead *headpa, *headpb;
   const char *var, *val;
   int x = 0;

   if (!to_cdr || !from_cdr) /* don't die if one of the pointers is null */
      return 0;

   headpa = &from_cdr->varshead;
   headpb = &to_cdr->varshead;

   AST_LIST_TRAVERSE(headpa,variables,entries) {
      if (variables &&
          (var = ast_var_name(variables)) && (val = ast_var_value(variables)) &&
          !ast_strlen_zero(var) && !ast_strlen_zero(val) &&
          (newvariable = ast_var_assign(var, val))) {
         AST_LIST_INSERT_HEAD(headpb, newvariable, entries);
         x++;
      }
   }

   return x;
}
int ast_cdr_data_add_structure ( struct ast_data tree,
struct ast_cdr cdr,
int  recur 
)
Parameters:
[in]treeWhere to insert the cdr.
[in]cdrThe cdr structure to insert in 'tree'.
[in]recurGo throw all the cdr levels.
Return values:
<0on error.
0on success.

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

{
   struct ast_cdr *tmpcdr;
   struct ast_data *level;
   struct ast_var_t *variables;
   const char *var, *val;
   int x = 1, i;
   char workspace[256];
   char *tmp;

   if (!cdr) {
      return -1;
   }

   for (tmpcdr = cdr; tmpcdr; tmpcdr = (recur ? tmpcdr->next : NULL)) {
      level = ast_data_add_node(tree, "level");
      if (!level) {
         continue;
      }

      ast_data_add_int(level, "level_number", x);

      AST_LIST_TRAVERSE(&tmpcdr->varshead, variables, entries) {
         if (variables && (var = ast_var_name(variables)) &&
               (val = ast_var_value(variables)) && !ast_strlen_zero(var)
               && !ast_strlen_zero(val)) {
            ast_data_add_str(level, var, val);
         } else {
            break;
         }
      }

      for (i = 0; cdr_readonly_vars[i]; i++) {
         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 */
         ast_cdr_getvar(tmpcdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
         if (!tmp) {
            continue;
         }
         ast_data_add_str(level, cdr_readonly_vars[i], tmp);
      }

      x++;
   }

   return 0;
}
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:
cdrWhich CDR to detach from the channel thread Prevents the channel thread from blocking on the CDR handling Returns nothing

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

{
   struct ast_cdr_batch_item *newtail;
   int curr;
   int submit_batch = 0;

   if (!cdr)
      return;

   /* maybe they disabled CDR stuff completely, so just drop it */
   if (!enabled) {
      ast_debug(1, "Dropping CDR !\n");
      ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
      ast_cdr_free(cdr);
      return;
   }

   /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
   if (!batchmode) {
      post_cdr(cdr);
      ast_cdr_free(cdr);
      return;
   }

   /* otherwise, each CDR gets put into a batch list (at the end) */
   ast_debug(1, "CDR detaching from this thread\n");

   /* we'll need a new tail for every CDR */
   if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
      post_cdr(cdr);
      ast_cdr_free(cdr);
      return;
   }

   /* don't traverse a whole list (just keep track of the tail) */
   ast_mutex_lock(&cdr_batch_lock);
   if (!batch)
      init_batch();
   if (!batch->head) {
      /* new batch is empty, so point the head at the new tail */
      batch->head = newtail;
   } else {
      /* already got a batch with something in it, so just append a new tail */
      batch->tail->next = newtail;
   }
   newtail->cdr = cdr;
   batch->tail = newtail;
   curr = batch->size++;

   /* if we have enough stuff to post, then do it */
   if (curr >= (batchsize - 1)) {
      submit_batch = 1;
   }
   ast_mutex_unlock(&cdr_batch_lock);

   /* Don't call submit_unscheduled_batch with the cdr_batch_lock held */
   if (submit_batch) {
      submit_unscheduled_batch();
   }
}
void ast_cdr_discard ( struct ast_cdr cdr)

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

Discard and free a CDR record.

Definition at line 499 of file cdr.c.

References ast_cdr_free_vars(), ast_free, and ast_cdr::next.

Referenced by ast_async_goto(), ast_bridge_call(), ast_cdr_merge(), ast_channel_destructor(), and ast_dummy_channel_destructor().

{
   while (cdr) {
      struct ast_cdr *next = cdr->next;

      ast_cdr_free_vars(cdr, 0);
      ast_free(cdr);
      cdr = next;
   }
}
char* ast_cdr_disp2str ( int  disposition)

Disposition to a string.

Parameters:
dispositioninput binary form Converts the binary form of a disposition to string form.
Returns:
a pointer to the string form

Definition at line 998 of file cdr.c.

References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_CONGESTION, 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().

{
   switch (disposition) {
   case AST_CDR_NULL:
      return "NO ANSWER"; /* by default, for backward compatibility */
   case AST_CDR_NOANSWER:
      return "NO ANSWER";
   case AST_CDR_FAILED:
      return "FAILED";
   case AST_CDR_BUSY:
      return "BUSY";
   case AST_CDR_ANSWERED:
      return "ANSWERED";
   case AST_CDR_CONGESTION:
      return "CONGESTION";
   }
   return "UNKNOWN";
}
int ast_cdr_disposition ( struct ast_cdr cdr,
int  cause 
)

Save the result of the call based on the AST_CAUSE_*.

Parameters:
cdrthe cdr you wish to associate with the call
causethe AST_CAUSE_* Returns nothing

Definition at line 826 of file cdr.c.

References AST_CAUSE_BUSY, AST_CAUSE_NO_ANSWER, AST_CAUSE_NORMAL, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION, ast_cdr_busy(), ast_cdr_congestion(), ast_cdr_noanswer(), and ast_cdr::next.

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

{
   int res = 0;

   for (; cdr; cdr = cdr->next) {
      switch (cause) {  /* handle all the non failure, busy cases, return 0 not to set disposition,
                     return -1 to set disposition to FAILED */
      case AST_CAUSE_BUSY:
         ast_cdr_busy(cdr);
         break;
      case AST_CAUSE_NO_ANSWER:
         ast_cdr_noanswer(cdr);
         break;
      case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
         ast_cdr_congestion(cdr);
         break;
      case AST_CAUSE_NORMAL:
         break;
      default:
         res = -1;
      }
   }
   return res;
}
struct ast_cdr* ast_cdr_dup ( struct ast_cdr cdr) [read]

Duplicate a record.

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 224 of file cdr.c.

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

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

{
   struct ast_cdr *newcdr;

   if (!cdr) /* don't die if we get a null cdr pointer */
      return NULL;
   newcdr = ast_cdr_alloc();
   if (!newcdr)
      return NULL;

   memcpy(newcdr, cdr, sizeof(*newcdr));
   /* The varshead is unusable, volatile even, after the memcpy so we take care of that here */
   memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
   ast_cdr_copy_vars(newcdr, cdr);
   newcdr->next = NULL;

   return newcdr;
}
struct ast_cdr* ast_cdr_dup_unique ( struct ast_cdr cdr) [read]

Duplicate a record and increment the sequence number.

Parameters:
cdrthe record to duplicate
Return values:
amalloc'd ast_cdr structure,
NULLon error (malloc failure)
See also:
ast_cdr_dup()
ast_cdr_dup_unique_swap()

Definition at line 201 of file cdr.c.

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_cdr_fork().

{
   struct ast_cdr *newcdr = ast_cdr_dup(cdr);
   if (!newcdr)
      return NULL;

   cdr_seq_inc(newcdr);
   return newcdr;
}
struct ast_cdr* ast_cdr_dup_unique_swap ( struct ast_cdr cdr) [read]

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

Parameters:
cdrthe record to duplicate
Return values:
amalloc'd ast_cdr structure,
NULLon 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 211 of file cdr.c.

References ast_cdr_dup(), and cdr_seq_inc().

Referenced by ast_bridge_call(), and ast_cdr_reset().

{
   struct ast_cdr *newcdr = ast_cdr_dup(cdr);
   if (!newcdr)
      return NULL;

   cdr_seq_inc(cdr);
   return newcdr;
}
void ast_cdr_end ( struct ast_cdr cdr)

End a call.

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

Definition at line 972 of file cdr.c.

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

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

{
   for ( ; cdr ; cdr = cdr->next) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      check_post(cdr);
      if (ast_tvzero(cdr->end))
         cdr->end = ast_tvnow();
      if (ast_tvzero(cdr->start)) {
         ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
         cdr->disposition = AST_CDR_FAILED;
      } else
         cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
      if (ast_tvzero(cdr->answer)) {
         if (cdr->disposition == AST_CDR_ANSWERED) {
            ast_log(LOG_WARNING, "CDR on channel '%s' has no answer time but is 'ANSWERED'\n", S_OR(cdr->channel, "<unknown>"));
            cdr->disposition = AST_CDR_FAILED;
         }
      } else {
         cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec;
         if (ast_test_flag(&ast_options, AST_OPT_FLAG_INITIATED_SECONDS))
            cdr->billsec += cdr->end.tv_usec > cdr->answer.tv_usec ? 1 : 0;
      }
   }
}
int ast_cdr_engine_init ( void  )

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

Definition at line 1687 of file cdr.c.

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

Referenced by main().

{
   sched = ast_sched_context_create();
   if (!sched) {
      ast_log(LOG_ERROR, "Unable to create schedule context.\n");
      return -1;
   }

   ast_cli_register(&cli_status);
   do_reload(0);
   ast_register_atexit(cdr_engine_shutdown);

   return 0;
}
int ast_cdr_engine_reload ( void  )

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

Definition at line 1709 of file cdr.c.

References do_reload().

{
   do_reload(1);
   return 0;
}
void ast_cdr_engine_term ( void  )

Submit any remaining CDRs and prepare for shutdown

Definition at line 1704 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by can_safely_quit(), and do_reload().

void ast_cdr_failed ( struct ast_cdr cdr)

Fail a call.

Parameters:
cdrthe 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 775 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_congestion(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten(), clear_caller(), handle_cause(), try_calling(), and wait_for_answer().

{
   for (; cdr; cdr = cdr->next) {
      check_post(cdr);
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         if (cdr->disposition < AST_CDR_FAILED)
            cdr->disposition = AST_CDR_FAILED;
      }
   }
}
char* ast_cdr_flags2str ( int  flag)

Converts AMA flag to printable string

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

{
   switch (flag) {
   case AST_CDR_OMIT:
      return "OMIT";
   case AST_CDR_BILLING:
      return "BILLING";
   case AST_CDR_DOCUMENTATION:
      return "DOCUMENTATION";
   }
   return "Unknown";
}
void ast_cdr_free ( struct ast_cdr cdr)

Free a CDR record.

Parameters:
cdrast_cdr structure to free Returns nothing

Definition at line 486 of file cdr.c.

References ast_cdr_free_vars(), ast_free, and ast_cdr::next.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

{

   while (cdr) {
      struct ast_cdr *next = cdr->next;

      ast_cdr_free_vars(cdr, 0);
      ast_free(cdr);
      cdr = next;
   }
}
void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

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

{

   /* clear variables */
   for (; cdr; cdr = recur ? cdr->next : NULL) {
      struct ast_var_t *vardata;
      struct varshead *headp = &cdr->varshead;
      while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
         ast_var_delete(vardata);
   }
}
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 275 of file cdr.c.

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

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

{
   const char *fmt = "%Y-%m-%d %T";
   const char *varbuf;

   if (!cdr)  /* don't die if the cdr is null */
      return;

   *ret = NULL;
   /* special vars (the ones from the struct ast_cdr when requested by name)
      I'd almost say we should convert all the stringed vals to vars */

   if (!strcasecmp(name, "clid"))
      ast_copy_string(workspace, cdr->clid, workspacelen);
   else if (!strcasecmp(name, "src"))
      ast_copy_string(workspace, cdr->src, workspacelen);
   else if (!strcasecmp(name, "dst"))
      ast_copy_string(workspace, cdr->dst, workspacelen);
   else if (!strcasecmp(name, "dcontext"))
      ast_copy_string(workspace, cdr->dcontext, workspacelen);
   else if (!strcasecmp(name, "channel"))
      ast_copy_string(workspace, cdr->channel, workspacelen);
   else if (!strcasecmp(name, "dstchannel"))
      ast_copy_string(workspace, cdr->dstchannel, workspacelen);
   else if (!strcasecmp(name, "lastapp"))
      ast_copy_string(workspace, cdr->lastapp, workspacelen);
   else if (!strcasecmp(name, "lastdata"))
      ast_copy_string(workspace, cdr->lastdata, workspacelen);
   else if (!strcasecmp(name, "start"))
      cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
   else if (!strcasecmp(name, "answer"))
      cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
   else if (!strcasecmp(name, "end"))
      cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
   else if (!strcasecmp(name, "duration")) {
      snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
   } else if (!strcasecmp(name, "billsec")) {
      snprintf(workspace, workspacelen, "%ld", (cdr->billsec || !ast_tvzero(cdr->end) || ast_tvzero(cdr->answer)) ? cdr->billsec : (long)ast_tvdiff_ms(ast_tvnow(), cdr->answer) / 1000); 
   } else if (!strcasecmp(name, "disposition")) {
      if (raw) {
         snprintf(workspace, workspacelen, "%ld", cdr->disposition);
      } else {
         ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
      }
   } else if (!strcasecmp(name, "amaflags")) {
      if (raw) {
         snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
      } else {
         ast_copy_string(workspace, ast_cdr_flags2str(cdr->amaflags), workspacelen);
      }
   } else if (!strcasecmp(name, "accountcode"))
      ast_copy_string(workspace, cdr->accountcode, workspacelen);
   else if (!strcasecmp(name, "peeraccount"))
      ast_copy_string(workspace, cdr->peeraccount, workspacelen);
   else if (!strcasecmp(name, "uniqueid"))
      ast_copy_string(workspace, cdr->uniqueid, workspacelen);
   else if (!strcasecmp(name, "linkedid"))
      ast_copy_string(workspace, cdr->linkedid, workspacelen);
   else if (!strcasecmp(name, "userfield"))
      ast_copy_string(workspace, cdr->userfield, workspacelen);
   else if (!strcasecmp(name, "sequence"))
      snprintf(workspace, workspacelen, "%d", cdr->sequence);
   else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
      ast_copy_string(workspace, varbuf, workspacelen);
   else
      workspace[0] = '\0';

   if (!ast_strlen_zero(workspace))
      *ret = workspace;
}
static const char* ast_cdr_getvar_internal ( struct ast_cdr cdr,
const char *  name,
int  recur 
) [static]

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

{
   if (ast_strlen_zero(name))
      return NULL;

   for (; cdr; cdr = recur ? cdr->next : NULL) {
      struct ast_var_t *variables;
      struct varshead *headp = &cdr->varshead;
      AST_LIST_TRAVERSE(headp, variables, entries) {
         if (!strcasecmp(name, ast_var_name(variables)))
            return ast_var_value(variables);
      }
   }

   return NULL;
}
int ast_cdr_init ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

Parameters:
cdrCall Detail Record to use for channel
chanChannel 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 936 of file cdr.c.

References ast_cdr::accountcode, ast_cdr::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_channel_accountcode(), ast_channel_amaflags(), ast_channel_context(), ast_channel_exten(), ast_channel_linkedid(), ast_channel_macrocontext(), ast_channel_macroexten(), ast_channel_name(), ast_channel_peeraccount(), ast_channel_uniqueid(), ast_copy_string(), ast_default_amaflags, AST_STATE_UP, ast_test_flag, cdr_seq_inc(), ast_cdr::channel, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::linkedid, ast_cdr::next, ast_cdr::peeraccount, S_OR, set_one_cid(), and ast_cdr::uniqueid.

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

{
   for ( ; cdr ; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         ast_copy_string(cdr->channel, ast_channel_name(c), sizeof(cdr->channel));
         set_one_cid(cdr, c);
         cdr_seq_inc(cdr);

         cdr->disposition = (ast_channel_state(c) == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
         cdr->amaflags = ast_channel_amaflags(c) ? ast_channel_amaflags(c) :  ast_default_amaflags;
         ast_copy_string(cdr->accountcode, ast_channel_accountcode(c), sizeof(cdr->accountcode));
         ast_copy_string(cdr->peeraccount, ast_channel_peeraccount(c), sizeof(cdr->peeraccount));
         /* Destination information */
         ast_copy_string(cdr->dst, S_OR(ast_channel_macroexten(c),ast_channel_exten(c)), sizeof(cdr->dst));
         ast_copy_string(cdr->dcontext, S_OR(ast_channel_macrocontext(c),ast_channel_context(c)), sizeof(cdr->dcontext));
         /* Unique call identifier */
         ast_copy_string(cdr->uniqueid, ast_channel_uniqueid(c), sizeof(cdr->uniqueid));
         /* Linked call identifier */
         ast_copy_string(cdr->linkedid, ast_channel_linkedid(c), sizeof(cdr->linkedid));
      }
   }
   return 0;
}
int ast_cdr_isset_congestion ( void  )

Definition at line 196 of file cdr.c.

References congestion.

{
   return congestion;
}
int ast_cdr_isset_unanswered ( void  )

Definition at line 191 of file cdr.c.

References unanswered.

Referenced by ring_entry(), and try_calling().

{
   return unanswered;
}
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:
tothe cdr to get the goodies
fromthe cdr to give the goodies

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

{
   struct ast_cdr *zcdr;
   struct ast_cdr *lto = NULL;
   struct ast_cdr *lfrom = NULL;
   int discard_from = 0;

   if (!to || !from)
      return;

   /* don't merge into locked CDR's -- it's bad business */
   if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
      zcdr = to; /* safety valve? */
      while (to->next) {
         lto = to;
         to = to->next;
      }

      if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
         ast_log(LOG_WARNING, "Merging into locked CDR... no choice.\n");
         to = zcdr; /* safety-- if all there are is locked CDR's, then.... ?? */
         lto = NULL;
      }
   }

   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED)) {
      struct ast_cdr *llfrom = NULL;
      discard_from = 1;
      if (lto) {
         /* insert the from stuff after lto */
         lto->next = from;
         lfrom = from;
         while (lfrom && lfrom->next) {
            if (!lfrom->next->next)
               llfrom = lfrom;
            lfrom = lfrom->next;
         }
         /* rip off the last entry and put a copy of the to at the end */
         if (llfrom) {
            llfrom->next = to;
         }
         from = lfrom;
      } else {
         /* save copy of the current *to cdr */
         struct ast_cdr tcdr;
         memcpy(&tcdr, to, sizeof(tcdr));
         /* copy in the locked from cdr */
         memcpy(to, from, sizeof(*to));
         lfrom = from;
         while (lfrom && lfrom->next) {
            if (!lfrom->next->next)
               llfrom = lfrom;
            lfrom = lfrom->next;
         }
         from->next = NULL;
         /* rip off the last entry and put a copy of the to at the end */
         if (llfrom == from) {
            to = to->next = ast_cdr_dup(&tcdr);
         } else if (llfrom) {
            to = llfrom->next = ast_cdr_dup(&tcdr);
         }
         from = lfrom;
      }
   }

   if (!ast_tvzero(from->start)) {
      if (!ast_tvzero(to->start)) {
         if (ast_tvcmp(to->start, from->start) > 0 ) {
            to->start = from->start; /* use the earliest time */
            from->start = ast_tv(0,0); /* we actively "steal" these values */
         }
         /* else nothing to do */
      } else {
         to->start = from->start;
         from->start = ast_tv(0,0); /* we actively "steal" these values */
      }
   }
   if (!ast_tvzero(from->answer)) {
      if (!ast_tvzero(to->answer)) {
         if (ast_tvcmp(to->answer, from->answer) > 0 ) {
            to->answer = from->answer; /* use the earliest time */
            from->answer = ast_tv(0,0); /* we actively "steal" these values */
         }
         /* we got the earliest answer time, so we'll settle for that? */
      } else {
         to->answer = from->answer;
         from->answer = ast_tv(0,0); /* we actively "steal" these values */
      }
   }
   if (!ast_tvzero(from->end)) {
      if (!ast_tvzero(to->end)) {
         if (ast_tvcmp(to->end, from->end) < 0 ) {
            to->end = from->end; /* use the latest time */
            from->end = ast_tv(0,0); /* we actively "steal" these values */
            to->duration = to->end.tv_sec - to->start.tv_sec;  /* don't forget to update the duration, billsec, when we set end */
            to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
         }
         /* else, nothing to do */
      } else {
         to->end = from->end;
         from->end = ast_tv(0,0); /* we actively "steal" these values */
         to->duration = to->end.tv_sec - to->start.tv_sec;
         to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
      }
   }
   if (to->disposition < from->disposition) {
      to->disposition = from->disposition;
      from->disposition = AST_CDR_NOANSWER;
   }
   if (ast_strlen_zero(to->lastapp) && !ast_strlen_zero(from->lastapp)) {
      ast_copy_string(to->lastapp, from->lastapp, sizeof(to->lastapp));
      from->lastapp[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->lastdata) && !ast_strlen_zero(from->lastdata)) {
      ast_copy_string(to->lastdata, from->lastdata, sizeof(to->lastdata));
      from->lastdata[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->dcontext) && !ast_strlen_zero(from->dcontext)) {
      ast_copy_string(to->dcontext, from->dcontext, sizeof(to->dcontext));
      from->dcontext[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->dstchannel) && !ast_strlen_zero(from->dstchannel)) {
      ast_copy_string(to->dstchannel, from->dstchannel, sizeof(to->dstchannel));
      from->dstchannel[0] = 0; /* theft */
   }
   if (!ast_strlen_zero(from->channel) && (ast_strlen_zero(to->channel) || !strncasecmp(from->channel, "Agent/", 6))) {
      ast_copy_string(to->channel, from->channel, sizeof(to->channel));
      from->channel[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->src) && !ast_strlen_zero(from->src)) {
      ast_copy_string(to->src, from->src, sizeof(to->src));
      from->src[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->clid) && !ast_strlen_zero(from->clid)) {
      ast_copy_string(to->clid, from->clid, sizeof(to->clid));
      from->clid[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->dst) && !ast_strlen_zero(from->dst)) {
      ast_copy_string(to->dst, from->dst, sizeof(to->dst));
      from->dst[0] = 0; /* theft */
   }
   if (!to->amaflags)
      to->amaflags = AST_CDR_DOCUMENTATION;
   if (!from->amaflags)
      from->amaflags = AST_CDR_DOCUMENTATION; /* make sure both amaflags are set to something (DOC is default) */
   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (to->amaflags == AST_CDR_DOCUMENTATION && from->amaflags != AST_CDR_DOCUMENTATION)) {
      to->amaflags = from->amaflags;
   }
   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->accountcode) && !ast_strlen_zero(from->accountcode))) {
      ast_copy_string(to->accountcode, from->accountcode, sizeof(to->accountcode));
   }
   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->peeraccount) && !ast_strlen_zero(from->peeraccount))) {
      ast_copy_string(to->peeraccount, from->peeraccount, sizeof(to->peeraccount));
   }
   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->userfield) && !ast_strlen_zero(from->userfield))) {
      ast_copy_string(to->userfield, from->userfield, sizeof(to->userfield));
   }
   /* flags, varsead, ? */
   cdr_merge_vars(from, to);

   if (ast_test_flag(from, AST_CDR_FLAG_KEEP_VARS))
      ast_set_flag(to, AST_CDR_FLAG_KEEP_VARS);
   if (ast_test_flag(from, AST_CDR_FLAG_POSTED))
      ast_set_flag(to, AST_CDR_FLAG_POSTED);
   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED))
      ast_set_flag(to, AST_CDR_FLAG_LOCKED);
   if (ast_test_flag(from, AST_CDR_FLAG_CHILD))
      ast_set_flag(to, AST_CDR_FLAG_CHILD);
   if (ast_test_flag(from, AST_CDR_FLAG_POST_DISABLED))
      ast_set_flag(to, AST_CDR_FLAG_POST_DISABLED);

   /* last, but not least, we need to merge any forked CDRs to the 'to' cdr */
   while (from->next) {
      /* just rip 'em off the 'from' and insert them on the 'to' */
      zcdr = from->next;
      from->next = zcdr->next;
      zcdr->next = NULL;
      /* zcdr is now ripped from the current list; */
      ast_cdr_append(to, zcdr);
   }
   if (discard_from)
      ast_cdr_discard(from);
}
void ast_cdr_noanswer ( struct ast_cdr cdr)

A call wasn't answered.

Parameters:
cdrthe 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 787 of file cdr.c.

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

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

{
   while (cdr) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         cdr->disposition = AST_CDR_NOANSWER;
      }
      cdr = cdr->next;
   }
}
int ast_cdr_register ( const char *  name,
const char *  desc,
ast_cdrbe  be 
)

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

Register a CDR handling engine.

Return values:
0on success.
-1on error

Definition at line 136 of file cdr.c.

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

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

{
   struct ast_cdr_beitem *i = NULL;

   if (!name)
      return -1;

   if (!be) {
      ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
      return -1;
   }

   AST_RWLIST_WRLOCK(&be_list);
   AST_RWLIST_TRAVERSE(&be_list, i, list) {
      if (!strcasecmp(name, i->name)) {
         ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
         AST_RWLIST_UNLOCK(&be_list);
         return -1;
      }
   }

   if (!(i = ast_calloc(1, sizeof(*i))))
      return -1;

   i->be = be;
   ast_copy_string(i->name, name, sizeof(i->name));
   ast_copy_string(i->desc, desc, sizeof(i->desc));

   AST_RWLIST_INSERT_HEAD(&be_list, i, list);
   AST_RWLIST_UNLOCK(&be_list);

   return 0;
}
void ast_cdr_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

Reset the detail record, optionally posting it first.

Parameters:
cdrwhich 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 1198 of file cdr.c.

References ast_cdr::answer, ast_cdr_detach(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POST_ENABLE, AST_CDR_FLAG_POSTED, ast_cdr_free_vars(), AST_CDR_NOANSWER, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, ast_cdr::next, and ast_cdr::start.

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

{
   struct ast_cdr *duplicate;
   struct ast_flags flags = { 0 };

   if (_flags)
      ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);

   for ( ; cdr ; cdr = cdr->next) {
      /* Detach if post is requested */
      if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
            ast_cdr_end(cdr);
            if ((duplicate = ast_cdr_dup_unique_swap(cdr))) {
               ast_cdr_detach(duplicate);
            }
            ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
         }

         /* enable CDR only */
         if (ast_test_flag(&flags, AST_CDR_FLAG_POST_ENABLE)) {
            ast_clear_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
            continue;
         }

         /* clear variables */
         if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
            ast_cdr_free_vars(cdr, 0);
         }

         /* Reset to initial state */
         ast_clear_flag(cdr, AST_FLAGS_ALL);
         memset(&cdr->start, 0, sizeof(cdr->start));
         memset(&cdr->end, 0, sizeof(cdr->end));
         memset(&cdr->answer, 0, sizeof(cdr->answer));
         cdr->billsec = 0;
         cdr->duration = 0;
         ast_cdr_start(cdr);
         cdr->disposition = AST_CDR_NOANSWER;
      }
   }
}
int ast_cdr_serialize_variables ( struct ast_cdr cdr,
struct ast_str **  buf,
char  delim,
char  sep,
int  recur 
)

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

{
   struct ast_var_t *variables;
   const char *var;
   char *tmp;
   char workspace[256];
   int total = 0, x = 0, i;

   ast_str_reset(*buf);

   for (; cdr; cdr = recur ? cdr->next : NULL) {
      if (++x > 1)
         ast_str_append(buf, 0, "\n");

      AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
         if (!(var = ast_var_name(variables))) {
            continue;
         }

         if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variables), ""), sep) < 0) {
            ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
            break;
         }

         total++;
      }

      for (i = 0; cdr_readonly_vars[i]; i++) {
         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 */
         ast_cdr_getvar(cdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
         if (!tmp)
            continue;

         if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, tmp, sep) < 0) {
            ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
            break;
         } else
            total++;
      }
   }

   return total;
}
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 1031 of file cdr.c.

References ast_cdr::accountcode, AST_CDR_FLAG_LOCKED, ast_channel_accountcode(), ast_channel_cdr(), ast_channel_name(), ast_channel_uniqueid(), ast_copy_string(), ast_manager_event, ast_strlen_zero(), ast_test_flag, EVENT_FLAG_CALL, and ast_cdr::next.

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

{
   struct ast_cdr *cdr = ast_channel_cdr(chan);
   const char *old_acct = "";

   if (!ast_strlen_zero(ast_channel_accountcode(chan))) {
      old_acct = ast_strdupa(ast_channel_accountcode(chan));
   }

   ast_channel_accountcode_set(chan, account);
   for ( ; cdr ; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         ast_copy_string(cdr->accountcode, ast_channel_accountcode(chan), sizeof(cdr->accountcode));
      }
   }
   /*** DOCUMENTATION
      <managerEventInstance>
         <synopsis>Raised when a CDR's AccountCode is changed.</synopsis>
      </managerEventInstance>
   ***/
   ast_manager_event(chan, EVENT_FLAG_CALL, "NewAccountCode",
         "Channel: %s\r\n"
         "Uniqueid: %s\r\n"
         "AccountCode: %s\r\n"
         "OldAccountCode: %s\r\n",
         ast_channel_name(chan), ast_channel_uniqueid(chan), ast_channel_accountcode(chan), old_acct);

   return 0;
}
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 1091 of file cdr.c.

References ast_cdr::amaflags, ast_cdr_amaflags2int(), AST_CDR_FLAG_LOCKED, ast_channel_cdr(), ast_test_flag, and ast_cdr::next.

Referenced by cdr_write(), and pbx_builtin_setamaflags().

{
   struct ast_cdr *cdr;
   int newflag = ast_cdr_amaflags2int(flag);
   if (newflag) {
      for (cdr = ast_channel_cdr(chan); cdr; cdr = cdr->next) {
         if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
            cdr->amaflags = newflag;
         }
      }
   }

   return 0;
}
void ast_cdr_setanswer ( struct ast_cdr cdr,
struct timeval  t 
)

Set the answer time for a call.

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

Definition at line 873 of file cdr.c.

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

Referenced by ast_bridge_call(), and dial_exec_full().

{

   for (; cdr; cdr = cdr->next) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
         continue;
      if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      check_post(cdr);
      cdr->answer = t;
   }
}
void ast_cdr_setapp ( struct ast_cdr cdr,
const char *  app,
const char *  data 
)

Set the last executed application.

Parameters:
cdrwhich cdr to act upon
appthe name of the app you wish to change it to
datathe 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 861 of file cdr.c.

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

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

{

   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp));
         ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata));
      }
   }
}
int ast_cdr_setcid ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

Parameters:
cdrCall Detail Record to use for channel
chanChannel 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 922 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().

{
   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         set_one_cid(cdr, c);
   }
   return 0;
}
void ast_cdr_setdestchan ( struct ast_cdr cdr,
const char *  chan 
)

Set the destination channel, if there was one.

Parameters:
cdrWhich cdr it's applied to
chanChannel to which dest will be Sets the destination channel the CDR is applied to Returns nothing

Definition at line 851 of file cdr.c.

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

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

{
   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
      }
   }
}
void ast_cdr_setdisposition ( struct ast_cdr cdr,
long int  disposition 
)

Set the disposition for a call.

Parameters:
cdrthe cdr you wish to associate with the call
dispositionthe new disposition Set the disposition on a call. NULL argument is just fine.

Definition at line 886 of file cdr.c.

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

Referenced by ast_bridge_call().

{

   for (; cdr; cdr = cdr->next) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      check_post(cdr);
      cdr->disposition = disposition;
   }
}
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 1061 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_channel_cdr(), ast_channel_name(), ast_channel_peeraccount(), ast_channel_uniqueid(), ast_copy_string(), ast_manager_event, ast_strlen_zero(), ast_test_flag, EVENT_FLAG_CALL, ast_cdr::next, and ast_cdr::peeraccount.

Referenced by cdr_write().

{
   struct ast_cdr *cdr = ast_channel_cdr(chan);
   const char *old_acct = "";

   if (!ast_strlen_zero(ast_channel_peeraccount(chan))) {
      old_acct = ast_strdupa(ast_channel_peeraccount(chan));
   }

   ast_channel_peeraccount_set(chan, account);
   for ( ; cdr ; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         ast_copy_string(cdr->peeraccount, ast_channel_peeraccount(chan), sizeof(cdr->peeraccount));
      }
   }
   /*** DOCUMENTATION
      <managerEventInstance>
         <synopsis>Raised when a CDR's PeerAccount is changed.</synopsis>
      </managerEventInstance>
   ***/
   ast_manager_event(chan, EVENT_FLAG_CALL, "NewPeerAccount",
         "Channel: %s\r\n"
         "Uniqueid: %s\r\n"
         "PeerAccount: %s\r\n"
         "OldPeerAccount: %s\r\n",
         ast_channel_name(chan), ast_channel_uniqueid(chan), ast_channel_peeraccount(chan), old_acct);

   return 0;
}
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 1106 of file cdr.c.

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

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

{
   struct ast_cdr *cdr = ast_channel_cdr(chan);

   for ( ; cdr ; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
   }

   return 0;
}
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 354 of file cdr.c.

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

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

{
   struct ast_var_t *newvariable;
   struct varshead *headp;
   int x;

   for (x = 0; cdr_readonly_vars[x]; x++) {
      if (!strcasecmp(name, cdr_readonly_vars[x])) {
         ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!.\n", name);
         return -1;
      }
   }

   if (!cdr) {
      ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n");
      return -1;
   }

   for (; cdr; cdr = recur ? cdr->next : NULL) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      headp = &cdr->varshead;
      AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
         if (!strcasecmp(ast_var_name(newvariable), name)) {
            /* there is already such a variable, delete it */
            AST_LIST_REMOVE_CURRENT(entries);
            ast_var_delete(newvariable);
            break;
         }
      }
      AST_LIST_TRAVERSE_SAFE_END;

      if (value && (newvariable = ast_var_assign(name, value))) {
         AST_LIST_INSERT_HEAD(headp, newvariable, entries);
      }
   }

   return 0;
}
void ast_cdr_specialized_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

Reset the detail record times, flags

Parameters:
cdrwhich 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 1241 of file cdr.c.

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

Referenced by ast_bridge_call().

{
   struct ast_flags flags = { 0 };

   if (_flags)
      ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);

   /* Reset to initial state */
   if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) { /* But do NOT lose the NoCDR() setting */
      ast_clear_flag(cdr, AST_FLAGS_ALL);
      ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
   } else {
      ast_clear_flag(cdr, AST_FLAGS_ALL);
   }

   memset(&cdr->start, 0, sizeof(cdr->start));
   memset(&cdr->end, 0, sizeof(cdr->end));
   memset(&cdr->answer, 0, sizeof(cdr->answer));
   cdr->billsec = 0;
   cdr->duration = 0;
   ast_cdr_start(cdr);
   cdr->disposition = AST_CDR_NULL;
}
void ast_cdr_start ( struct ast_cdr cdr)

Start a call.

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

Definition at line 738 of file cdr.c.

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

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

{
   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         cdr->start = ast_tvnow();
      }
   }
}
void ast_cdr_submit_batch ( int  shutdown)

Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines.

Parameters:
shutdownWhether or not we are shutting down Blocks the asterisk shutdown procedures until the CDR data is submitted. Returns nothing

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

{
   struct ast_cdr_batch_item *oldbatchitems = NULL;
   pthread_t batch_post_thread = AST_PTHREADT_NULL;

   /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
   if (!batch || !batch->head)
      return;

   /* move the old CDRs aside, and prepare a new CDR batch */
   ast_mutex_lock(&cdr_batch_lock);
   oldbatchitems = batch->head;
   reset_batch();
   ast_mutex_unlock(&cdr_batch_lock);

   /* if configured, spawn a new thread to post these CDRs,
      also try to save as much as possible if we are shutting down safely */
   if (batchscheduleronly || do_shutdown) {
      ast_debug(1, "CDR single-threaded batch processing begins now\n");
      do_batch_backend_process(oldbatchitems);
   } else {
      if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
         ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
         do_batch_backend_process(oldbatchitems);
      } else {
         ast_debug(1, "CDR multi-threaded batch processing begins now\n");
      }
   }
}
void ast_cdr_unregister ( const char *  name)

Unregister a CDR handling engine.

unregister a CDR driver

Definition at line 171 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, and ast_cdr_beitem::name.

Referenced by load_config(), odbc_load_module(), reload(), tds_unload_module(), and unload_module().

{
   struct ast_cdr_beitem *i = NULL;

   AST_RWLIST_WRLOCK(&be_list);
   AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
      if (!strcasecmp(name, i->name)) {
         AST_RWLIST_REMOVE_CURRENT(list);
         break;
      }
   }
   AST_RWLIST_TRAVERSE_SAFE_END;
   AST_RWLIST_UNLOCK(&be_list);

   if (i) {
      ast_verb(2, "Unregistered '%s' CDR backend\n", name);
      ast_free(i);
   }
}
static void cdr_engine_shutdown ( void  ) [static]
static void cdr_get_tv ( struct timeval  when,
const char *  fmt,
char *  buf,
int  bufsize 
) [static]

Definition at line 260 of file cdr.c.

References ast_localtime(), and ast_strftime().

Referenced by ast_cdr_getvar().

{
   if (fmt == NULL) {   /* raw mode */
      snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
   } else {
      if (when.tv_sec) {
         struct ast_tm tm;

         ast_localtime(&when, &tm, NULL);
         ast_strftime(buf, bufsize, fmt, &tm);
      }
   }
}
static void cdr_merge_vars ( struct ast_cdr to,
struct ast_cdr from 
) [static]

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

{
   struct ast_var_t *variablesfrom,*variablesto;
   struct varshead *headpfrom = &to->varshead;
   struct varshead *headpto = &from->varshead;
   AST_LIST_TRAVERSE_SAFE_BEGIN(headpfrom, variablesfrom, entries) {
      /* for every var in from, stick it in to */
      const char *fromvarname, *fromvarval;
      const char *tovarname = NULL, *tovarval = NULL;
      fromvarname = ast_var_name(variablesfrom);
      fromvarval = ast_var_value(variablesfrom);
      tovarname = 0;

      /* now, quick see if that var is in the 'to' cdr already */
      AST_LIST_TRAVERSE(headpto, variablesto, entries) {

         /* now, quick see if that var is in the 'to' cdr already */
         if ( strcasecmp(fromvarname, ast_var_name(variablesto)) == 0 ) {
            tovarname = ast_var_name(variablesto);
            tovarval = ast_var_value(variablesto);
            break;
         }
      }
      if (tovarname && strcasecmp(fromvarval,tovarval) != 0) {  /* this message here to see how irritating the userbase finds it */
         ast_log(LOG_NOTICE, "Merging CDR's: variable %s value %s dropped in favor of value %s\n", tovarname, fromvarval, tovarval);
         continue;
      } else if (tovarname && strcasecmp(fromvarval,tovarval) == 0) /* if they are the same, the job is done */
         continue;

      /* rip this var out of the from cdr, and stick it in the to cdr */
      AST_LIST_MOVE_CURRENT(headpto, entries);
   }
   AST_LIST_TRAVERSE_SAFE_END;
}
static int cdr_seq_inc ( struct ast_cdr cdr) [static]
int check_cdr_enabled ( void  )

Return TRUE if CDR subsystem is enabled.

Definition at line 126 of file cdr.c.

References enabled.

Referenced by action_coresettings(), and handle_show_settings().

{
   return enabled;
}
static void check_post ( struct ast_cdr cdr) [static]

print a warning if cdr already posted

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

{
   if (!cdr)
      return;
   if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
      ast_log(LOG_NOTICE, "CDR on channel '%s' already posted\n", S_OR(cdr->channel, "<unknown>"));
}
static void* do_batch_backend_process ( void *  data) [static]

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

{
   struct ast_cdr_batch_item *processeditem;
   struct ast_cdr_batch_item *batchitem = data;

   /* Push each CDR into storage mechanism(s) and free all the memory */
   while (batchitem) {
      post_cdr(batchitem->cdr);
      ast_cdr_free(batchitem->cdr);
      processeditem = batchitem;
      batchitem = batchitem->next;
      ast_free(processeditem);
   }

   return NULL;
}
static void* do_cdr ( void *  data) [static]

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

{
   struct timespec timeout;
   int schedms;
   int numevents = 0;

   for (;;) {
      struct timeval now;
      schedms = ast_sched_wait(sched);
      /* this shouldn't happen, but provide a 1 second default just in case */
      if (schedms <= 0)
         schedms = 1000;
      now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
      timeout.tv_sec = now.tv_sec;
      timeout.tv_nsec = now.tv_usec * 1000;
      /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
      ast_mutex_lock(&cdr_pending_lock);
      ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
      numevents = ast_sched_runq(sched);
      ast_mutex_unlock(&cdr_pending_lock);
      ast_debug(2, "Processed %d scheduled CDR batches from the run queue\n", numevents);
   }

   return NULL;
}
static void do_reload ( int  reload) [static]

Definition at line 1547 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_browse(), BATCH_SAFE_SHUTDOWN_DEFAULT, BATCH_SCHEDULER_ONLY_DEFAULT, BATCH_SIZE_DEFAULT, BATCH_TIME_DEFAULT, batchmode, BATCHMODE_DEFAULT, batchsafeshutdown, batchscheduleronly, batchsize, batchtime, cdr_batch_lock, cdr_pending_cond, cdr_sched, cdr_sched_lock, cdr_thread, cli_submit, config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, congestion, CONGESTION_DEFAULT, do_cdr(), enabled, ENABLED_DEFAULT, EVENT_FLAG_SYSTEM, LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_event, ast_variable::name, ast_variable::next, submit_scheduled_batch(), unanswered, UNANSWERED_DEFAULT, and ast_variable::value.

Referenced by ast_cdr_engine_init(), and ast_cdr_engine_reload().

{
   struct ast_config *config;
   struct ast_variable *v;
   int cfg_size;
   int cfg_time;
   int was_enabled;
   int was_batchmode;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

   if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
      return;
   }

   ast_mutex_lock(&cdr_batch_lock);

   was_enabled = enabled;
   was_batchmode = batchmode;

   batchsize = BATCH_SIZE_DEFAULT;
   batchtime = BATCH_TIME_DEFAULT;
   batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
   batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
   enabled = ENABLED_DEFAULT;
   batchmode = BATCHMODE_DEFAULT;
   unanswered = UNANSWERED_DEFAULT;
   congestion = CONGESTION_DEFAULT;

   if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
      ast_mutex_unlock(&cdr_batch_lock);
      return;
   }

   /* don't run the next scheduled CDR posting while reloading */
   ast_mutex_lock(&cdr_sched_lock);
   AST_SCHED_DEL(sched, cdr_sched);
   ast_mutex_unlock(&cdr_sched_lock);

   for (v = ast_variable_browse(config, "general"); v; v = v->next) {
      if (!strcasecmp(v->name, "enable")) {
         enabled = ast_true(v->value);
      } else if (!strcasecmp(v->name, "unanswered")) {
         unanswered = ast_true(v->value);
      } else if (!strcasecmp(v->name, "congestion")) {
         congestion = ast_true(v->value);
      } else if (!strcasecmp(v->name, "batch")) {
         batchmode = ast_true(v->value);
      } else if (!strcasecmp(v->name, "scheduleronly")) {
         batchscheduleronly = ast_true(v->value);
      } else if (!strcasecmp(v->name, "safeshutdown")) {
         batchsafeshutdown = ast_true(v->value);
      } else if (!strcasecmp(v->name, "size")) {
         if (sscanf(v->value, "%30d", &cfg_size) < 1) {
            ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", v->value);
         } else if (cfg_size < 0) {
            ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
         } else {
            batchsize = cfg_size;
         }
      } else if (!strcasecmp(v->name, "time")) {
         if (sscanf(v->value, "%30d", &cfg_time) < 1) {
            ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", v->value);
         } else if (cfg_time < 0) {
            ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
         } else {
            batchtime = cfg_time;
         }
      } else if (!strcasecmp(v->name, "endbeforehexten")) {
         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
      } else if (!strcasecmp(v->name, "initiatedseconds")) {
         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INITIATED_SECONDS);
      }
   }

   if (enabled && !batchmode) {
      ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
   } else if (enabled && batchmode) {
      ast_mutex_lock(&cdr_sched_lock);
      cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
      ast_mutex_unlock(&cdr_sched_lock);
      ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
   } else {
      ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
   }

   /* if this reload enabled the CDR batch mode, create the background thread
      if it does not exist */
   if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
      ast_cond_init(&cdr_pending_cond, NULL);
      if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
         ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
         ast_mutex_lock(&cdr_sched_lock);
         AST_SCHED_DEL(sched, cdr_sched);
         ast_mutex_unlock(&cdr_sched_lock);
      } else {
         ast_cli_register(&cli_submit);
         ast_register_atexit(ast_cdr_engine_term);
      }
   /* if this reload disabled the CDR and/or batch mode and there is a background thread,
      kill it */
   } else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
      /* wake up the thread so it will exit */
      pthread_cancel(cdr_thread);
      pthread_kill(cdr_thread, SIGURG);
      pthread_join(cdr_thread, NULL);
      cdr_thread = AST_PTHREADT_NULL;
      ast_cond_destroy(&cdr_pending_cond);
      ast_cli_unregister(&cli_submit);
      ast_unregister_atexit(ast_cdr_engine_term);
      /* if leaving batch mode, then post the CDRs in the batch,
         and don't reschedule, since we are stopping CDR logging */
      if (!batchmode && was_batchmode) {
         ast_cdr_engine_term();
      }
   }

   ast_mutex_unlock(&cdr_batch_lock);
   ast_config_destroy(config);
   manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: CDR\r\nMessage: CDR subsystem reload requested\r\n");
}
static char* handle_cli_status ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1464 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, congestion, enabled, ESS, ast_cli_args::fd, ast_cdr_beitem::name, ast_cdr_batch::size, unanswered, and ast_cli_entry::usage.

{
   struct ast_cdr_beitem *beitem=NULL;
   int cnt=0;
   long nextbatchtime=0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "cdr show status";
      e->usage =
         "Usage: cdr show status\n"
         "  Displays the Call Detail Record engine system status.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc > 3)
      return CLI_SHOWUSAGE;

   ast_cli(a->fd, "\n");
   ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
   ast_cli(a->fd, "----------------------------------\n");
   ast_cli(a->fd, "  Logging:                    %s\n", enabled ? "Enabled" : "Disabled");
   ast_cli(a->fd, "  Mode:                       %s\n", batchmode ? "Batch" : "Simple");
   if (enabled) {
      ast_cli(a->fd, "  Log unanswered calls:       %s\n", unanswered ? "Yes" : "No");
      ast_cli(a->fd, "  Log congestion:             %s\n\n", congestion ? "Yes" : "No");
      if (batchmode) {
         ast_cli(a->fd, "* Batch Mode Settings\n");
         ast_cli(a->fd, "  -------------------\n");
         if (batch)
            cnt = batch->size;
         if (cdr_sched > -1)
            nextbatchtime = ast_sched_when(sched, cdr_sched);
         ast_cli(a->fd, "  Safe shutdown:              %s\n", batchsafeshutdown ? "Enabled" : "Disabled");
         ast_cli(a->fd, "  Threading model:            %s\n", batchscheduleronly ? "Scheduler only" : "Scheduler plus separate threads");
         ast_cli(a->fd, "  Current batch size:         %d record%s\n", cnt, ESS(cnt));
         ast_cli(a->fd, "  Maximum batch size:         %d record%s\n", batchsize, ESS(batchsize));
         ast_cli(a->fd, "  Maximum batch time:         %d second%s\n", batchtime, ESS(batchtime));
         ast_cli(a->fd, "  Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
      }
      ast_cli(a->fd, "* Registered Backends\n");
      ast_cli(a->fd, "  -------------------\n");
      AST_RWLIST_RDLOCK(&be_list);
      if (AST_RWLIST_EMPTY(&be_list)) {
         ast_cli(a->fd, "    (none)\n");
      } else {
         AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
            ast_cli(a->fd, "    %s\n", beitem->name);
         }
      }
      AST_RWLIST_UNLOCK(&be_list);
      ast_cli(a->fd, "\n");
   }

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

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

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "cdr submit";
      e->usage =
         "Usage: cdr submit\n"
         "       Posts all pending batched CDR data to the configured CDR backend engine modules.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   if (a->argc > 2)
      return CLI_SHOWUSAGE;

   submit_unscheduled_batch();
   ast_cli(a->fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");

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

Definition at line 1291 of file cdr.c.

References ast_malloc, batch, and reset_batch().

Referenced by ast_cdr_detach().

{
   /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
   if (!(batch = ast_malloc(sizeof(*batch))))
      return -1;

   reset_batch();

   return 0;
}
static void post_cdr ( struct ast_cdr cdr) [static]

Definition at line 1167 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::next, and unanswered.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

{
   struct ast_cdr_beitem *i;

   for ( ; cdr ; cdr = cdr->next) {
      if (!unanswered && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
         /* For people, who don't want to see unanswered single-channel events */
         ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
         continue;
      }

      /* don't post CDRs that are for dialed channels unless those
       * channels were originated from asterisk (pbx_spool, manager,
       * cli) */
      if (ast_test_flag(cdr, AST_CDR_FLAG_DIALED) && !ast_test_flag(cdr, AST_CDR_FLAG_ORIGINATED)) {
         ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
         continue;
      }

      check_post(cdr);
      ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
      if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
         continue;
      AST_RWLIST_RDLOCK(&be_list);
      AST_RWLIST_TRAVERSE(&be_list, i, list) {
         i->be(cdr);
      }
      AST_RWLIST_UNLOCK(&be_list);
   }
}
static void reset_batch ( void  ) [static]
Note:
Don't call without cdr_batch_lock

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

{
   batch->size = 0;
   batch->head = NULL;
   batch->tail = NULL;
}
static void set_one_cid ( struct ast_cdr cdr,
struct ast_channel c 
) [static]

Definition at line 898 of file cdr.c.

References ast_callerid_merge(), ast_cdr_setvar(), ast_channel_caller(), ast_channel_dialed(), ast_copy_string(), ast_cdr::clid, ast_cdr_beitem::name, S_COR, S_OR, ast_cdr::src, and ast_party_dialed::str.

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

{
   const char *num;

   if (!cdr) {
      return;
   }

   /* Grab source from ANI or normal Caller*ID */
   num = S_COR(ast_channel_caller(c)->ani.number.valid, ast_channel_caller(c)->ani.number.str,
      S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL));
   ast_callerid_merge(cdr->clid, sizeof(cdr->clid),
      S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, NULL), num, "");
   ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src));
   ast_cdr_setvar(cdr, "dnid", S_OR(ast_channel_dialed(c)->number.str, ""), 0);

   if (ast_channel_caller(c)->id.subaddress.valid) {
      ast_cdr_setvar(cdr, "callingsubaddr", S_OR(ast_channel_caller(c)->id.subaddress.str, ""), 0);
   }
   if (ast_channel_dialed(c)->subaddress.valid) {
      ast_cdr_setvar(cdr, "calledsubaddr", S_OR(ast_channel_dialed(c)->subaddress.str, ""), 0);
   }
}
static int submit_scheduled_batch ( const void *  data) [static]

Definition at line 1349 of file cdr.c.

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

Referenced by do_reload(), and submit_unscheduled_batch().

{
   ast_cdr_submit_batch(0);
   /* manually reschedule from this point in time */
   ast_mutex_lock(&cdr_sched_lock);
   cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
   ast_mutex_unlock(&cdr_sched_lock);
   /* returning zero so the scheduler does not automatically reschedule */
   return 0;
}
static void submit_unscheduled_batch ( void  ) [static]

Do not hold the batch lock while calling this function

Definition at line 1361 of file cdr.c.

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

Referenced by ast_cdr_detach(), and handle_cli_submit().

{
   /* Prevent two deletes from happening at the same time */
   ast_mutex_lock(&cdr_sched_lock);
   /* this is okay since we are not being called from within the scheduler */
   AST_SCHED_DEL(sched, cdr_sched);
   /* schedule the submission to occur ASAP (1 ms) */
   cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
   ast_mutex_unlock(&cdr_sched_lock);

   /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
   ast_mutex_lock(&cdr_pending_lock);
   ast_cond_signal(&cdr_pending_cond);
   ast_mutex_unlock(&cdr_pending_lock);
}

Variable Documentation

Definition at line 63 of file cdr.c.

Referenced by __ast_channel_alloc_ap().

Default AMA flag for billing records (CDR's)

Definition at line 62 of file cdr.c.

Referenced by __ast_channel_alloc_ap(), ast_bridge_call(), and ast_cdr_init().

const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1 [static]

Definition at line 116 of file cdr.c.

Referenced by do_reload().

const int BATCH_SCHEDULER_ONLY_DEFAULT = 0 [static]

Definition at line 113 of file cdr.c.

Referenced by do_reload().

const int BATCH_SIZE_DEFAULT = 100 [static]

Definition at line 107 of file cdr.c.

Referenced by do_reload().

const int BATCH_TIME_DEFAULT = 300 [static]

Definition at line 110 of file cdr.c.

Referenced by do_reload().

int batchmode [static]

Definition at line 97 of file cdr.c.

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

const int BATCHMODE_DEFAULT = 0 [static]

Definition at line 98 of file cdr.c.

Referenced by do_reload().

int batchsafeshutdown [static]

Definition at line 115 of file cdr.c.

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

int batchscheduleronly [static]

Definition at line 112 of file cdr.c.

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

int batchsize [static]

Definition at line 106 of file cdr.c.

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

int batchtime [static]

Definition at line 109 of file cdr.c.

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

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

Definition at line 120 of file cdr.c.

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

Definition at line 124 of file cdr.c.

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

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

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

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

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

Definition at line 118 of file cdr.c.

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

int cdr_sequence = 0 [static]

Definition at line 86 of file cdr.c.

Referenced by cdr_seq_inc().

pthread_t cdr_thread = AST_PTHREADT_NULL [static]

Definition at line 92 of file cdr.c.

Referenced by cdr_engine_shutdown(), and do_reload().

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

Definition at line 1545 of file cdr.c.

Referenced by ast_cdr_engine_init(), and cdr_engine_shutdown().

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

Definition at line 1544 of file cdr.c.

Referenced by cdr_engine_shutdown(), and do_reload().

int congestion [static]

Definition at line 103 of file cdr.c.

Referenced by ast_cdr_congestion(), ast_cdr_isset_congestion(), do_reload(), and handle_cli_status().

const int CONGESTION_DEFAULT = 0 [static]

Definition at line 104 of file cdr.c.

Referenced by do_reload().

const int ENABLED_DEFAULT = 1 [static]

Definition at line 95 of file cdr.c.

Referenced by do_reload().

struct ast_sched_context* sched [static]

Definition at line 90 of file cdr.c.

int unanswered [static]

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

Referenced by do_reload().