#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"
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 |
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_cdr * | ast_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_cdr * | ast_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) |
void | ast_cdr_discard (struct ast_cdr *cdr) |
Discard and free a CDR record. | |
char * | ast_cdr_disp2str (int disposition) |
int | ast_cdr_disposition (struct ast_cdr *cdr, int cause) |
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). | |
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_isset_unanswered (void) |
void | ast_cdr_merge (struct ast_cdr *to, struct ast_cdr *from) |
void | ast_cdr_noanswer (struct ast_cdr *cdr) |
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, char *buf, size_t size, 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_setanswer (struct ast_cdr *cdr, struct timeval t) |
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) |
void | ast_cdr_setdisposition (struct ast_cdr *cdr, long int disposition) |
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_specialized_reset (struct ast_cdr *cdr, struct ast_flags *_flags) |
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 void | cdr_get_tv (struct timeval tv, const char *fmt, char *buf, int bufsize) |
static void | cdr_merge_vars (struct ast_cdr *to, struct ast_cdr *from) |
int | check_cdr_enabled () |
Return TRUE if CDR subsystem is enabled. | |
static void | check_post (struct ast_cdr *cdr) |
print a warning if cdr already posted | |
static void * | do_batch_backend_process (void *data) |
static void * | do_cdr (void *data) |
static int | do_reload (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 (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_batch * | batch |
static int | batchmode |
static int | batchsafeshutdown |
static int | batchscheduleronly |
static int | batchsize |
static int | batchtime |
static ast_mutex_t | cdr_batch_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
static ast_cond_t | cdr_pending_cond |
static ast_mutex_t | cdr_pending_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
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_context * | sched |
static int | unanswered |
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.
#define BATCH_SAFE_SHUTDOWN_DEFAULT 1 |
#define BATCH_SCHEDULER_ONLY_DEFAULT 0 |
#define BATCH_SIZE_DEFAULT 100 |
#define BATCH_TIME_DEFAULT 300 |
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 469 of file cdr.c.
References ast_calloc, ast_log(), and LOG_ERROR.
Referenced by __agent_start_monitoring(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_dup(), builtin_blindtransfer(), clear_caller(), findmeexec(), and start_monitor_exec().
00470 { 00471 struct ast_cdr *x = ast_calloc(1, sizeof(struct ast_cdr)); 00472 if (!x) 00473 ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n"); 00474 return x; 00475 }
int ast_cdr_amaflags2int | ( | const char * | flag | ) |
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 1020 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(), process_dahdi(), and set_config().
01021 { 01022 if (!strcasecmp(flag, "default")) 01023 return 0; 01024 if (!strcasecmp(flag, "omit")) 01025 return AST_CDR_OMIT; 01026 if (!strcasecmp(flag, "billing")) 01027 return AST_CDR_BILLING; 01028 if (!strcasecmp(flag, "documentation")) 01029 return AST_CDR_DOCUMENTATION; 01030 return -1; 01031 }
void ast_cdr_answer | ( | struct ast_cdr * | cdr | ) |
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 705 of file cdr.c.
References AST_CDR_ANSWERED, AST_CDR_FLAG_ANSLOCKED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_test_flag, ast_tvnow(), ast_tvzero(), check_post(), and ast_cdr::next.
Referenced by __ast_request_and_dial(), ast_answer(), and ast_bridge_call().
00706 { 00707 00708 for (; cdr; cdr = cdr->next) { 00709 if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED)) 00710 continue; 00711 if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 00712 continue; 00713 check_post(cdr); 00714 if (cdr->disposition < AST_CDR_ANSWERED) 00715 cdr->disposition = AST_CDR_ANSWERED; 00716 if (ast_tvzero(cdr->answer)) 00717 cdr->answer = ast_tvnow(); 00718 } 00719 }
Definition at line 1131 of file cdr.c.
References ast_cdr::next.
Referenced by ast_cdr_fork(), and ast_cdr_merge().
01132 { 01133 struct ast_cdr *ret; 01134 01135 if (cdr) { 01136 ret = cdr; 01137 01138 while (cdr->next) 01139 cdr = cdr->next; 01140 cdr->next = newcdr; 01141 } else { 01142 ret = newcdr; 01143 } 01144 01145 return ret; 01146 }
int ast_cdr_appenduserfield | ( | struct ast_channel * | chan, | |
const char * | userfield | |||
) |
Definition at line 986 of file cdr.c.
References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, len(), ast_cdr::next, and ast_cdr::userfield.
Referenced by action_setcdruserfield(), and appendcdruserfield_exec().
00987 { 00988 struct ast_cdr *cdr = chan->cdr; 00989 00990 for ( ; cdr ; cdr = cdr->next) { 00991 int len = strlen(cdr->userfield); 00992 00993 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 00994 ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len); 00995 } 00996 00997 return 0; 00998 }
void ast_cdr_busy | ( | struct ast_cdr * | cdr | ) |
cdr | the cdr you wish to associate with the call Marks the channel disposition as "BUSY" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application. Returns nothing |
Definition at line 721 of file cdr.c.
References AST_CDR_BUSY, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), and ast_cdr::next.
Referenced by __ast_request_and_dial(), ast_cdr_disposition(), pbx_builtin_busy(), and ring_entry().
00722 { 00723 00724 for (; cdr; cdr = cdr->next) { 00725 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 00726 check_post(cdr); 00727 cdr->disposition = AST_CDR_BUSY; 00728 } 00729 } 00730 }
Definition at line 346 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().
00347 { 00348 struct ast_var_t *variables, *newvariable = NULL; 00349 struct varshead *headpa, *headpb; 00350 const char *var, *val; 00351 int x = 0; 00352 00353 if (!to_cdr || !from_cdr) /* don't die if one of the pointers is null */ 00354 return 0; 00355 00356 headpa = &from_cdr->varshead; 00357 headpb = &to_cdr->varshead; 00358 00359 AST_LIST_TRAVERSE(headpa,variables,entries) { 00360 if (variables && 00361 (var = ast_var_name(variables)) && (val = ast_var_value(variables)) && 00362 !ast_strlen_zero(var) && !ast_strlen_zero(val)) { 00363 newvariable = ast_var_assign(var, val); 00364 AST_LIST_INSERT_HEAD(headpb, newvariable, entries); 00365 x++; 00366 } 00367 } 00368 00369 return x; 00370 }
void ast_cdr_detach | ( | struct ast_cdr * | cdr | ) |
cdr | Which CDR to detach from the channel thread Prevents the channel thread from blocking on the CDR handling Returns nothing |
Definition at line 1242 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, cdr_batch_lock, 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_bridge_call(), ast_cdr_reset(), ast_hangup(), and ast_pbx_outgoing_cdr_failed().
01243 { 01244 struct ast_cdr_batch_item *newtail; 01245 int curr; 01246 01247 if (!cdr) 01248 return; 01249 01250 /* maybe they disabled CDR stuff completely, so just drop it */ 01251 if (!enabled) { 01252 if (option_debug) 01253 ast_log(LOG_DEBUG, "Dropping CDR !\n"); 01254 ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED); 01255 ast_cdr_free(cdr); 01256 return; 01257 } 01258 01259 /* post stuff immediately if we are not in batch mode, this is legacy behaviour */ 01260 if (!batchmode) { 01261 post_cdr(cdr); 01262 ast_cdr_free(cdr); 01263 return; 01264 } 01265 01266 /* otherwise, each CDR gets put into a batch list (at the end) */ 01267 if (option_debug) 01268 ast_log(LOG_DEBUG, "CDR detaching from this thread\n"); 01269 01270 /* we'll need a new tail for every CDR */ 01271 if (!(newtail = ast_calloc(1, sizeof(*newtail)))) { 01272 post_cdr(cdr); 01273 ast_cdr_free(cdr); 01274 return; 01275 } 01276 01277 /* don't traverse a whole list (just keep track of the tail) */ 01278 ast_mutex_lock(&cdr_batch_lock); 01279 if (!batch) 01280 init_batch(); 01281 if (!batch->head) { 01282 /* new batch is empty, so point the head at the new tail */ 01283 batch->head = newtail; 01284 } else { 01285 /* already got a batch with something in it, so just append a new tail */ 01286 batch->tail->next = newtail; 01287 } 01288 newtail->cdr = cdr; 01289 batch->tail = newtail; 01290 curr = batch->size++; 01291 ast_mutex_unlock(&cdr_batch_lock); 01292 01293 /* if we have enough stuff to post, then do it */ 01294 if (curr >= (batchsize - 1)) 01295 submit_unscheduled_batch(); 01296 }
void ast_cdr_discard | ( | struct ast_cdr * | cdr | ) |
Discard and free a CDR record.
cdr | ast_cdr structure to free Returns nothing -- same as free, but no checks or complaints |
Definition at line 458 of file cdr.c.
References ast_cdr_free_vars(), free, ast_cdr_beitem::next, and ast_cdr::next.
Referenced by ast_async_goto(), ast_bridge_call(), ast_cdr_merge(), and ast_channel_free().
00459 { 00460 while (cdr) { 00461 struct ast_cdr *next = cdr->next; 00462 00463 ast_cdr_free_vars(cdr, 0); 00464 free(cdr); 00465 cdr = next; 00466 } 00467 }
char* ast_cdr_disp2str | ( | int | disposition | ) |
disposition | input binary form Converts the binary form of a disposition to string form. Returns a pointer to the string form |
Definition at line 915 of file cdr.c.
References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_FAILED, AST_CDR_NOANSWER, and AST_CDR_NULL.
Referenced by ast_cdr_getvar(), build_csv_record(), build_query(), build_radius_record(), csv_log(), manager_log(), pgsql_log(), and tds_log().
00916 { 00917 switch (disposition) { 00918 case AST_CDR_NULL: 00919 return "NO ANSWER"; /* by default, for backward compatibility */ 00920 case AST_CDR_NOANSWER: 00921 return "NO ANSWER"; 00922 case AST_CDR_FAILED: 00923 return "FAILED"; 00924 case AST_CDR_BUSY: 00925 return "BUSY"; 00926 case AST_CDR_ANSWERED: 00927 return "ANSWERED"; 00928 } 00929 return "UNKNOWN"; 00930 }
int ast_cdr_disposition | ( | struct ast_cdr * | cdr, | |
int | cause | |||
) |
cdr | the cdr you wish to associate with the call | |
cause | the AST_CAUSE_* Returns nothing |
Definition at line 760 of file cdr.c.
References AST_CAUSE_BUSY, AST_CAUSE_NO_ANSWER, AST_CAUSE_NORMAL, ast_cdr_busy(), ast_cdr_noanswer(), and ast_cdr::next.
Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), clear_caller(), and findmeexec().
00761 { 00762 int res = 0; 00763 00764 for (; cdr; cdr = cdr->next) { 00765 switch(cause) { /* handle all the non failure, busy cases, return 0 not to set disposition, 00766 return -1 to set disposition to FAILED */ 00767 case AST_CAUSE_BUSY: 00768 ast_cdr_busy(cdr); 00769 break; 00770 case AST_CAUSE_NO_ANSWER: 00771 ast_cdr_noanswer(cdr); 00772 break; 00773 case AST_CAUSE_NORMAL: 00774 break; 00775 default: 00776 res = -1; 00777 } 00778 } 00779 return res; 00780 }
Duplicate a record Returns a malloc'd ast_cdr structure, returns NULL on error (malloc failure).
Duplicate a CDR record
Definition at line 177 of file cdr.c.
References ast_cdr_alloc(), and ast_cdr_copy_vars().
Referenced by ast_async_goto(), ast_bridge_call(), ast_cdr_fork(), ast_cdr_merge(), and ast_cdr_reset().
00178 { 00179 struct ast_cdr *newcdr; 00180 00181 if (!cdr) /* don't die if we get a null cdr pointer */ 00182 return NULL; 00183 newcdr = ast_cdr_alloc(); 00184 if (!newcdr) 00185 return NULL; 00186 00187 memcpy(newcdr, cdr, sizeof(*newcdr)); 00188 /* The varshead is unusable, volatile even, after the memcpy so we take care of that here */ 00189 memset(&newcdr->varshead, 0, sizeof(newcdr->varshead)); 00190 ast_cdr_copy_vars(newcdr, cdr); 00191 newcdr->next = NULL; 00192 00193 return newcdr; 00194 }
void ast_cdr_end | ( | struct ast_cdr * | cdr | ) |
cdr | the cdr you have associated the call with Registers the end of call time in the cdr structure. Returns nothing |
Definition at line 892 of file cdr.c.
References AST_CDR_ANSWERED, AST_CDR_FAILED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_log(), ast_test_flag, ast_tvnow(), ast_tvzero(), check_post(), LOG_WARNING, ast_cdr::next, and S_OR.
Referenced by __ast_request_and_dial(), ast_bridge_call(), ast_cdr_fork(), ast_cdr_reset(), ast_hangup(), ast_pbx_outgoing_cdr_failed(), clear_caller(), and findmeexec().
00893 { 00894 for ( ; cdr ; cdr = cdr->next) { 00895 if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 00896 continue; 00897 check_post(cdr); 00898 if (ast_tvzero(cdr->end)) 00899 cdr->end = ast_tvnow(); 00900 if (ast_tvzero(cdr->start)) { 00901 ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>")); 00902 cdr->disposition = AST_CDR_FAILED; 00903 } else 00904 cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec; 00905 if (ast_tvzero(cdr->answer)) { 00906 if (cdr->disposition == AST_CDR_ANSWERED) { 00907 ast_log(LOG_WARNING, "CDR on channel '%s' has no answer time but is 'ANSWERED'\n", S_OR(cdr->channel, "<unknown>")); 00908 cdr->disposition = AST_CDR_FAILED; 00909 } 00910 } else 00911 cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec; 00912 } 00913 }
int ast_cdr_engine_init | ( | void | ) |
Load the configuration file cdr.conf and possibly start the CDR scheduling thread
Definition at line 1500 of file cdr.c.
References ast_cli_register(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), cdr_batch_lock, cli_status, do_reload(), init_batch(), LOG_ERROR, and sched_context_create().
Referenced by main().
01501 { 01502 int res; 01503 01504 sched = sched_context_create(); 01505 if (!sched) { 01506 ast_log(LOG_ERROR, "Unable to create schedule context.\n"); 01507 return -1; 01508 } 01509 01510 ast_cli_register(&cli_status); 01511 01512 res = do_reload(); 01513 if (res) { 01514 ast_mutex_lock(&cdr_batch_lock); 01515 res = init_batch(); 01516 ast_mutex_unlock(&cdr_batch_lock); 01517 } 01518 01519 return res; 01520 }
int ast_cdr_engine_reload | ( | void | ) |
Reload the configuration file cdr.conf and start/stop CDR scheduling thread
Definition at line 1529 of file cdr.c.
References do_reload().
01530 { 01531 return do_reload(); 01532 }
void ast_cdr_engine_term | ( | void | ) |
Submit any remaining CDRs and prepare for shutdown
Definition at line 1524 of file cdr.c.
References ast_cdr_submit_batch(), and batchsafeshutdown.
Referenced by do_reload(), and quit_handler().
01525 { 01526 ast_cdr_submit_batch(batchsafeshutdown); 01527 }
void ast_cdr_failed | ( | struct ast_cdr * | cdr | ) |
cdr | the cdr you wish to associate with the call Marks the channel disposition as "FAILED" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application. Returns nothing |
Definition at line 732 of file cdr.c.
References AST_CDR_FAILED, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), ast_cdr::disposition, and ast_cdr::next.
Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten(), clear_caller(), findmeexec(), and wait_for_answer().
00733 { 00734 for (; cdr; cdr = cdr->next) { 00735 check_post(cdr); 00736 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 00737 if (cdr->disposition < AST_CDR_FAILED) 00738 cdr->disposition = AST_CDR_FAILED; 00739 } 00740 } 00741 }
char* ast_cdr_flags2str | ( | int | flag | ) |
Converts AMA flag to printable string
Definition at line 933 of file cdr.c.
References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.
Referenced by _sip_show_peer(), ast_cdr_getvar(), build_csv_record(), build_radius_record(), csv_log(), manager_log(), sip_show_user(), and tds_log().
00934 { 00935 switch(flag) { 00936 case AST_CDR_OMIT: 00937 return "OMIT"; 00938 case AST_CDR_BILLING: 00939 return "BILLING"; 00940 case AST_CDR_DOCUMENTATION: 00941 return "DOCUMENTATION"; 00942 } 00943 return "Unknown"; 00944 }
void ast_cdr_free | ( | struct ast_cdr * | cdr | ) |
Free a CDR record.
cdr | ast_cdr structure to free Returns nothing |
Definition at line 438 of file cdr.c.
References AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, ast_cdr_free_vars(), ast_test_flag, ast_tvzero(), ast_verbose(), ast_cdr::channel, ast_cdr::end, free, ast_cdr_beitem::next, ast_cdr::next, option_verbose, S_OR, ast_cdr::start, and VERBOSE_PREFIX_2.
Referenced by ast_cdr_detach(), and do_batch_backend_process().
00439 { 00440 00441 while (cdr) { 00442 struct ast_cdr *next = cdr->next; 00443 char *chan = S_OR(cdr->channel, "<unknown>"); 00444 if (option_verbose > 1 && !ast_test_flag(cdr, AST_CDR_FLAG_POSTED) && !ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) 00445 ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' not posted\n", chan); 00446 if (option_verbose > 1 && ast_tvzero(cdr->end)) 00447 ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' lacks end\n", chan); 00448 if (option_verbose > 1 && ast_tvzero(cdr->start)) 00449 ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' lacks start\n", chan); 00450 00451 ast_cdr_free_vars(cdr, 0); 00452 free(cdr); 00453 cdr = next; 00454 } 00455 }
void ast_cdr_free_vars | ( | struct ast_cdr * | cdr, | |
int | recur | |||
) |
Definition at line 417 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().
00418 { 00419 00420 /* clear variables */ 00421 for (; cdr; cdr = recur ? cdr->next : NULL) { 00422 struct ast_var_t *vardata; 00423 struct varshead *headp = &cdr->varshead; 00424 while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) 00425 ast_var_delete(vardata); 00426 } 00427 }
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 229 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_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::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.
Referenced by ast_cdr_serialize_variables(), and cdr_read().
00230 { 00231 const char *fmt = "%Y-%m-%d %T"; 00232 const char *varbuf; 00233 00234 if (!cdr) /* don't die if the cdr is null */ 00235 return; 00236 00237 *ret = NULL; 00238 /* special vars (the ones from the struct ast_cdr when requested by name) 00239 I'd almost say we should convert all the stringed vals to vars */ 00240 00241 if (!strcasecmp(name, "clid")) 00242 ast_copy_string(workspace, cdr->clid, workspacelen); 00243 else if (!strcasecmp(name, "src")) 00244 ast_copy_string(workspace, cdr->src, workspacelen); 00245 else if (!strcasecmp(name, "dst")) 00246 ast_copy_string(workspace, cdr->dst, workspacelen); 00247 else if (!strcasecmp(name, "dcontext")) 00248 ast_copy_string(workspace, cdr->dcontext, workspacelen); 00249 else if (!strcasecmp(name, "channel")) 00250 ast_copy_string(workspace, cdr->channel, workspacelen); 00251 else if (!strcasecmp(name, "dstchannel")) 00252 ast_copy_string(workspace, cdr->dstchannel, workspacelen); 00253 else if (!strcasecmp(name, "lastapp")) 00254 ast_copy_string(workspace, cdr->lastapp, workspacelen); 00255 else if (!strcasecmp(name, "lastdata")) 00256 ast_copy_string(workspace, cdr->lastdata, workspacelen); 00257 else if (!strcasecmp(name, "start")) 00258 cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen); 00259 else if (!strcasecmp(name, "answer")) 00260 cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen); 00261 else if (!strcasecmp(name, "end")) 00262 cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen); 00263 else if (!strcasecmp(name, "duration")) 00264 snprintf(workspace, workspacelen, "%ld", cdr->duration); 00265 else if (!strcasecmp(name, "billsec")) 00266 snprintf(workspace, workspacelen, "%ld", cdr->billsec); 00267 else if (!strcasecmp(name, "disposition")) { 00268 if (raw) { 00269 snprintf(workspace, workspacelen, "%ld", cdr->disposition); 00270 } else { 00271 ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen); 00272 } 00273 } else if (!strcasecmp(name, "amaflags")) { 00274 if (raw) { 00275 snprintf(workspace, workspacelen, "%ld", cdr->amaflags); 00276 } else { 00277 ast_copy_string(workspace, ast_cdr_flags2str(cdr->amaflags), workspacelen); 00278 } 00279 } else if (!strcasecmp(name, "accountcode")) 00280 ast_copy_string(workspace, cdr->accountcode, workspacelen); 00281 else if (!strcasecmp(name, "uniqueid")) 00282 ast_copy_string(workspace, cdr->uniqueid, workspacelen); 00283 else if (!strcasecmp(name, "userfield")) 00284 ast_copy_string(workspace, cdr->userfield, workspacelen); 00285 else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur))) 00286 ast_copy_string(workspace, varbuf, workspacelen); 00287 else 00288 workspace[0] = '\0'; 00289 00290 if (!ast_strlen_zero(workspace)) 00291 *ret = workspace; 00292 }
static const char* ast_cdr_getvar_internal | ( | struct ast_cdr * | cdr, | |
const char * | name, | |||
int | recur | |||
) | [static] |
Definition at line 196 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().
00197 { 00198 if (ast_strlen_zero(name)) 00199 return NULL; 00200 00201 for (; cdr; cdr = recur ? cdr->next : NULL) { 00202 struct ast_var_t *variables; 00203 struct varshead *headp = &cdr->varshead; 00204 AST_LIST_TRAVERSE(headp, variables, entries) { 00205 if (!strcasecmp(name, ast_var_name(variables))) 00206 return ast_var_value(variables); 00207 } 00208 } 00209 00210 return NULL; 00211 }
int ast_cdr_init | ( | struct ast_cdr * | cdr, | |
struct ast_channel * | chan | |||
) |
Initialize based on a channel.
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 857 of file cdr.c.
References ast_channel::_state, ast_channel::accountcode, ast_channel::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_copy_string(), AST_STATE_UP, ast_test_flag, ast_cdr::channel, ast_channel::context, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::name, ast_cdr::next, S_OR, set_one_cid(), and ast_channel::uniqueid.
Referenced by __ast_request_and_dial(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().
00858 { 00859 char *chan; 00860 00861 for ( ; cdr ; cdr = cdr->next) { 00862 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 00863 chan = S_OR(cdr->channel, "<unknown>"); 00864 ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel)); 00865 set_one_cid(cdr, c); 00866 00867 cdr->disposition = (c->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NOANSWER; 00868 cdr->amaflags = c->amaflags ? c->amaflags : ast_default_amaflags; 00869 ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode)); 00870 /* Destination information */ 00871 ast_copy_string(cdr->dst, S_OR(c->macroexten,c->exten), sizeof(cdr->dst)); 00872 ast_copy_string(cdr->dcontext, S_OR(c->macrocontext,c->context), sizeof(cdr->dcontext)); 00873 /* Unique call identifier */ 00874 ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid)); 00875 } 00876 } 00877 return 0; 00878 }
int ast_cdr_isset_unanswered | ( | void | ) |
Definition at line 169 of file cdr.c.
References unanswered.
Referenced by ring_entry(), and try_calling().
00170 { 00171 return unanswered; 00172 }
Move the non-null data from the "from" cdr to the "to" cdr
to | the cdr to get the goodies | |
from | the cdr to give the goodies |
Definition at line 513 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::src, ast_cdr::start, and ast_cdr::userfield.
00514 { 00515 struct ast_cdr *zcdr; 00516 struct ast_cdr *lto = NULL; 00517 struct ast_cdr *lfrom = NULL; 00518 int discard_from = 0; 00519 00520 if (!to || !from) 00521 return; 00522 00523 /* don't merge into locked CDR's -- it's bad business */ 00524 if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) { 00525 zcdr = to; /* safety valve? */ 00526 while (to->next) { 00527 lto = to; 00528 to = to->next; 00529 } 00530 00531 if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) { 00532 ast_log(LOG_WARNING, "Merging into locked CDR... no choice."); 00533 to = zcdr; /* safety-- if all there are is locked CDR's, then.... ?? */ 00534 lto = NULL; 00535 } 00536 } 00537 00538 if (ast_test_flag(from, AST_CDR_FLAG_LOCKED)) { 00539 discard_from = 1; 00540 if (lto) { 00541 struct ast_cdr *llfrom = NULL; 00542 /* insert the from stuff after lto */ 00543 lto->next = from; 00544 lfrom = from; 00545 while (lfrom && lfrom->next) { 00546 if (!lfrom->next->next) 00547 llfrom = lfrom; 00548 lfrom = lfrom->next; 00549 } 00550 /* rip off the last entry and put a copy of the to at the end */ 00551 llfrom->next = to; 00552 from = lfrom; 00553 } else { 00554 /* save copy of the current *to cdr */ 00555 struct ast_cdr tcdr; 00556 struct ast_cdr *llfrom = NULL; 00557 memcpy(&tcdr, to, sizeof(tcdr)); 00558 /* copy in the locked from cdr */ 00559 memcpy(to, from, sizeof(*to)); 00560 lfrom = from; 00561 while (lfrom && lfrom->next) { 00562 if (!lfrom->next->next) 00563 llfrom = lfrom; 00564 lfrom = lfrom->next; 00565 } 00566 from->next = NULL; 00567 /* rip off the last entry and put a copy of the to at the end */ 00568 if (llfrom == from) 00569 to = to->next = ast_cdr_dup(&tcdr); 00570 else 00571 to = llfrom->next = ast_cdr_dup(&tcdr); 00572 from = lfrom; 00573 } 00574 } 00575 00576 if (!ast_tvzero(from->start)) { 00577 if (!ast_tvzero(to->start)) { 00578 if (ast_tvcmp(to->start, from->start) > 0 ) { 00579 to->start = from->start; /* use the earliest time */ 00580 from->start = ast_tv(0,0); /* we actively "steal" these values */ 00581 } 00582 /* else nothing to do */ 00583 } else { 00584 to->start = from->start; 00585 from->start = ast_tv(0,0); /* we actively "steal" these values */ 00586 } 00587 } 00588 if (!ast_tvzero(from->answer)) { 00589 if (!ast_tvzero(to->answer)) { 00590 if (ast_tvcmp(to->answer, from->answer) > 0 ) { 00591 to->answer = from->answer; /* use the earliest time */ 00592 from->answer = ast_tv(0,0); /* we actively "steal" these values */ 00593 } 00594 /* we got the earliest answer time, so we'll settle for that? */ 00595 } else { 00596 to->answer = from->answer; 00597 from->answer = ast_tv(0,0); /* we actively "steal" these values */ 00598 } 00599 } 00600 if (!ast_tvzero(from->end)) { 00601 if (!ast_tvzero(to->end)) { 00602 if (ast_tvcmp(to->end, from->end) < 0 ) { 00603 to->end = from->end; /* use the latest time */ 00604 from->end = ast_tv(0,0); /* we actively "steal" these values */ 00605 to->duration = to->end.tv_sec - to->start.tv_sec; /* don't forget to update the duration, billsec, when we set end */ 00606 to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec; 00607 } 00608 /* else, nothing to do */ 00609 } else { 00610 to->end = from->end; 00611 from->end = ast_tv(0,0); /* we actively "steal" these values */ 00612 to->duration = to->end.tv_sec - to->start.tv_sec; 00613 to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec; 00614 } 00615 } 00616 if (to->disposition < from->disposition) { 00617 to->disposition = from->disposition; 00618 from->disposition = AST_CDR_NOANSWER; 00619 } 00620 if (ast_strlen_zero(to->lastapp) && !ast_strlen_zero(from->lastapp)) { 00621 ast_copy_string(to->lastapp, from->lastapp, sizeof(to->lastapp)); 00622 from->lastapp[0] = 0; /* theft */ 00623 } 00624 if (ast_strlen_zero(to->lastdata) && !ast_strlen_zero(from->lastdata)) { 00625 ast_copy_string(to->lastdata, from->lastdata, sizeof(to->lastdata)); 00626 from->lastdata[0] = 0; /* theft */ 00627 } 00628 if (ast_strlen_zero(to->dcontext) && !ast_strlen_zero(from->dcontext)) { 00629 ast_copy_string(to->dcontext, from->dcontext, sizeof(to->dcontext)); 00630 from->dcontext[0] = 0; /* theft */ 00631 } 00632 if (ast_strlen_zero(to->dstchannel) && !ast_strlen_zero(from->dstchannel)) { 00633 ast_copy_string(to->dstchannel, from->dstchannel, sizeof(to->dstchannel)); 00634 from->dstchannel[0] = 0; /* theft */ 00635 } 00636 if (!ast_strlen_zero(from->channel) && (ast_strlen_zero(to->channel) || !strncasecmp(from->channel, "Agent/", 6))) { 00637 ast_copy_string(to->channel, from->channel, sizeof(to->channel)); 00638 from->channel[0] = 0; /* theft */ 00639 } 00640 if (ast_strlen_zero(to->src) && !ast_strlen_zero(from->src)) { 00641 ast_copy_string(to->src, from->src, sizeof(to->src)); 00642 from->src[0] = 0; /* theft */ 00643 } 00644 if (ast_strlen_zero(to->clid) && !ast_strlen_zero(from->clid)) { 00645 ast_copy_string(to->clid, from->clid, sizeof(to->clid)); 00646 from->clid[0] = 0; /* theft */ 00647 } 00648 if (ast_strlen_zero(to->dst) && !ast_strlen_zero(from->dst)) { 00649 ast_copy_string(to->dst, from->dst, sizeof(to->dst)); 00650 from->dst[0] = 0; /* theft */ 00651 } 00652 if (!to->amaflags) 00653 to->amaflags = AST_CDR_DOCUMENTATION; 00654 if (!from->amaflags) 00655 from->amaflags = AST_CDR_DOCUMENTATION; /* make sure both amaflags are set to something (DOC is default) */ 00656 if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (to->amaflags == AST_CDR_DOCUMENTATION && from->amaflags != AST_CDR_DOCUMENTATION)) { 00657 to->amaflags = from->amaflags; 00658 } 00659 if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->accountcode) && !ast_strlen_zero(from->accountcode))) { 00660 ast_copy_string(to->accountcode, from->accountcode, sizeof(to->accountcode)); 00661 } 00662 if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->userfield) && !ast_strlen_zero(from->userfield))) { 00663 ast_copy_string(to->userfield, from->userfield, sizeof(to->userfield)); 00664 } 00665 /* flags, varsead, ? */ 00666 cdr_merge_vars(from, to); 00667 00668 if (ast_test_flag(from, AST_CDR_FLAG_KEEP_VARS)) 00669 ast_set_flag(to, AST_CDR_FLAG_KEEP_VARS); 00670 if (ast_test_flag(from, AST_CDR_FLAG_POSTED)) 00671 ast_set_flag(to, AST_CDR_FLAG_POSTED); 00672 if (ast_test_flag(from, AST_CDR_FLAG_LOCKED)) 00673 ast_set_flag(to, AST_CDR_FLAG_LOCKED); 00674 if (ast_test_flag(from, AST_CDR_FLAG_CHILD)) 00675 ast_set_flag(to, AST_CDR_FLAG_CHILD); 00676 if (ast_test_flag(from, AST_CDR_FLAG_POST_DISABLED)) 00677 ast_set_flag(to, AST_CDR_FLAG_POST_DISABLED); 00678 00679 /* last, but not least, we need to merge any forked CDRs to the 'to' cdr */ 00680 while (from->next) { 00681 /* just rip 'em off the 'from' and insert them on the 'to' */ 00682 zcdr = from->next; 00683 from->next = zcdr->next; 00684 zcdr->next = NULL; 00685 /* zcdr is now ripped from the current list; */ 00686 ast_cdr_append(to, zcdr); 00687 } 00688 if (discard_from) 00689 ast_cdr_discard(from); 00690 }
void ast_cdr_noanswer | ( | struct ast_cdr * | cdr | ) |
cdr | the cdr you wish to associate with the call Marks the channel disposition as "NO ANSWER" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application. |
Definition at line 743 of file cdr.c.
References AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_strlen_zero(), ast_test_flag, ast_cdr::channel, check_post(), ast_cdr::disposition, and ast_cdr::next.
Referenced by ast_cdr_disposition(), try_calling(), and wait_for_answer().
00744 { 00745 char *chan; 00746 00747 while (cdr) { 00748 chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>"; 00749 check_post(cdr); 00750 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 00751 cdr->disposition = AST_CDR_NOANSWER; 00752 } 00753 cdr = cdr->next; 00754 } 00755 }
int ast_cdr_register | ( | const char * | name, | |
const char * | desc, | |||
ast_cdrbe | be | |||
) |
Register a CDR driver. Each registered CDR driver generates a CDR
Definition at line 113 of file cdr.c.
References ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_cdr_beitem::list, LOG_WARNING, and ast_cdr_beitem::name.
Referenced by load_module(), odbc_load_module(), process_my_load_module(), and tds_load_module().
00114 { 00115 struct ast_cdr_beitem *i; 00116 00117 if (!name) 00118 return -1; 00119 if (!be) { 00120 ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name); 00121 return -1; 00122 } 00123 00124 AST_LIST_LOCK(&be_list); 00125 AST_LIST_TRAVERSE(&be_list, i, list) { 00126 if (!strcasecmp(name, i->name)) 00127 break; 00128 } 00129 AST_LIST_UNLOCK(&be_list); 00130 00131 if (i) { 00132 ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name); 00133 return -1; 00134 } 00135 00136 if (!(i = ast_calloc(1, sizeof(*i)))) 00137 return -1; 00138 00139 i->be = be; 00140 ast_copy_string(i->name, name, sizeof(i->name)); 00141 ast_copy_string(i->desc, desc, sizeof(i->desc)); 00142 00143 AST_LIST_LOCK(&be_list); 00144 AST_LIST_INSERT_HEAD(&be_list, i, list); 00145 AST_LIST_UNLOCK(&be_list); 00146 00147 return 0; 00148 }
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 1070 of file cdr.c.
References ast_cdr::answer, ast_cdr_detach(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POSTED, ast_cdr_free_vars(), AST_CDR_NOANSWER, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, ast_flags::flags, ast_cdr::next, and ast_cdr::start.
Referenced by ast_cdr_fork(), disa_exec(), and pbx_builtin_resetcdr().
01071 { 01072 struct ast_cdr *dup; 01073 struct ast_flags flags = { 0 }; 01074 01075 if (_flags) 01076 ast_copy_flags(&flags, _flags, AST_FLAGS_ALL); 01077 01078 for ( ; cdr ; cdr = cdr->next) { 01079 /* Detach if post is requested */ 01080 if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 01081 if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) { 01082 ast_cdr_end(cdr); 01083 if ((dup = ast_cdr_dup(cdr))) { 01084 ast_cdr_detach(dup); 01085 } 01086 ast_set_flag(cdr, AST_CDR_FLAG_POSTED); 01087 } 01088 01089 /* clear variables */ 01090 if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) { 01091 ast_cdr_free_vars(cdr, 0); 01092 } 01093 01094 /* Reset to initial state */ 01095 ast_clear_flag(cdr, AST_FLAGS_ALL); 01096 memset(&cdr->start, 0, sizeof(cdr->start)); 01097 memset(&cdr->end, 0, sizeof(cdr->end)); 01098 memset(&cdr->answer, 0, sizeof(cdr->answer)); 01099 cdr->billsec = 0; 01100 cdr->duration = 0; 01101 ast_cdr_start(cdr); 01102 cdr->disposition = AST_CDR_NOANSWER; 01103 } 01104 } 01105 }
int ast_cdr_serialize_variables | ( | struct ast_cdr * | cdr, | |
char * | buf, | |||
size_t | size, | |||
char | delim, | |||
char | sep, | |||
int | recur | |||
) |
Definition at line 372 of file cdr.c.
References ast_build_string(), ast_cdr_getvar(), AST_LIST_TRAVERSE, ast_log(), 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(), and handle_showchan_deprecated().
00373 { 00374 struct ast_var_t *variables; 00375 const char *var; 00376 char *tmp; 00377 char workspace[256]; 00378 int total = 0, x = 0, i; 00379 00380 memset(buf, 0, size); 00381 00382 for (; cdr; cdr = recur ? cdr->next : NULL) { 00383 if (++x > 1) 00384 ast_build_string(&buf, &size, "\n"); 00385 00386 AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) { 00387 if (!(var = ast_var_name(variables))) { 00388 continue; 00389 } 00390 00391 if (ast_build_string(&buf, &size, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variables), ""), sep)) { 00392 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n"); 00393 break; 00394 } 00395 00396 total++; 00397 } 00398 00399 for (i = 0; cdr_readonly_vars[i]; i++) { 00400 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 */ 00401 ast_cdr_getvar(cdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0); 00402 if (!tmp) 00403 continue; 00404 00405 if (ast_build_string(&buf, &size, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, tmp, sep)) { 00406 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n"); 00407 break; 00408 } else 00409 total++; 00410 } 00411 } 00412 00413 return total; 00414 }
int ast_cdr_setaccount | ( | struct ast_channel * | chan, | |
const char * | account | |||
) |
Definition at line 946 of file cdr.c.
References accountcode, ast_cdr::accountcode, ast_channel::accountcode, AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_string_field_set, ast_test_flag, ast_channel::cdr, 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(), cdr_write(), and rpt_call().
00947 { 00948 struct ast_cdr *cdr = chan->cdr; 00949 00950 ast_string_field_set(chan, accountcode, account); 00951 for ( ; cdr ; cdr = cdr->next) { 00952 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 00953 ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode)); 00954 } 00955 } 00956 return 0; 00957 }
int ast_cdr_setamaflags | ( | struct ast_channel * | chan, | |
const char * | flag | |||
) |
Definition at line 959 of file cdr.c.
References ast_cdr::amaflags, ast_cdr_amaflags2int(), AST_CDR_FLAG_LOCKED, ast_test_flag, ast_channel::cdr, and ast_cdr::next.
Referenced by cdr_write(), and pbx_builtin_setamaflags().
00960 { 00961 struct ast_cdr *cdr; 00962 int newflag = ast_cdr_amaflags2int(flag); 00963 if (newflag) { 00964 for (cdr = chan->cdr; cdr; cdr = cdr->next) { 00965 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 00966 cdr->amaflags = newflag; 00967 } 00968 } 00969 } 00970 00971 return 0; 00972 }
void ast_cdr_setanswer | ( | struct ast_cdr * | cdr, | |
struct timeval | t | |||
) |
cdr | the cdr you wish to associate with the call | |
t | the answer time Starts all CDR stuff necessary for doing CDR when answering a call NULL argument is just fine. |
Definition at line 803 of file cdr.c.
References AST_CDR_FLAG_ANSLOCKED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), and ast_cdr::next.
Referenced by ast_bridge_call().
00804 { 00805 00806 for (; cdr; cdr = cdr->next) { 00807 if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED)) 00808 continue; 00809 if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 00810 continue; 00811 check_post(cdr); 00812 cdr->answer = t; 00813 } 00814 }
void ast_cdr_setapp | ( | struct ast_cdr * | cdr, | |
char * | app, | |||
char * | data | |||
) |
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 791 of file cdr.c.
References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, check_post(), ast_cdr::next, and S_OR.
Referenced by __ast_request_and_dial(), agi_handle_command(), clear_caller(), findmeexec(), and pbx_exec().
00792 { 00793 00794 for (; cdr; cdr = cdr->next) { 00795 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 00796 check_post(cdr); 00797 ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp)); 00798 ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata)); 00799 } 00800 } 00801 }
int ast_cdr_setcid | ( | struct ast_cdr * | cdr, | |
struct ast_channel * | chan | |||
) |
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 848 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_set_callerid(), and callerid_write().
00849 { 00850 for (; cdr; cdr = cdr->next) { 00851 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 00852 set_one_cid(cdr, c); 00853 } 00854 return 0; 00855 }
void ast_cdr_setdestchan | ( | struct ast_cdr * | cdr, | |
const char * | chan | |||
) |
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 782 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 park_exec(), and ring_entry().
00783 { 00784 for (; cdr; cdr = cdr->next) { 00785 check_post(cdr); 00786 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 00787 ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel)); 00788 } 00789 }
void ast_cdr_setdisposition | ( | struct ast_cdr * | cdr, | |
long int | disposition | |||
) |
cdr | the cdr you wish to associate with the call | |
disposition | the new disposition Set the disposition on a call. NULL argument is just fine. |
Definition at line 816 of file cdr.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), and ast_cdr::next.
Referenced by ast_bridge_call().
00817 { 00818 00819 for (; cdr; cdr = cdr->next) { 00820 if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 00821 continue; 00822 check_post(cdr); 00823 cdr->disposition = disposition; 00824 } 00825 }
int ast_cdr_setuserfield | ( | struct ast_channel * | chan, | |
const char * | userfield | |||
) |
Definition at line 974 of file cdr.c.
References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, ast_cdr::next, and ast_cdr::userfield.
Referenced by __agent_start_monitoring(), action_setcdruserfield(), cdr_write(), handle_request_info(), setcdruserfield_exec(), and start_monitor_exec().
00975 { 00976 struct ast_cdr *cdr = chan->cdr; 00977 00978 for ( ; cdr ; cdr = cdr->next) { 00979 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 00980 ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield)); 00981 } 00982 00983 return 0; 00984 }
int ast_cdr_setvar | ( | struct ast_cdr * | cdr, | |
const char * | name, | |||
const char * | value, | |||
int | recur | |||
) |
Set a CDR channel variable
Definition at line 302 of file cdr.c.
References AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_test_flag, ast_var_assign(), ast_var_delete(), ast_var_name(), cdr_readonly_vars, LOG_ERROR, and ast_cdr::next.
Referenced by ast_cdr_fork(), cdr_write(), and set_one_cid().
00303 { 00304 struct ast_var_t *newvariable; 00305 struct varshead *headp; 00306 int x; 00307 00308 if (!cdr) /* don't die if the cdr is null */ 00309 return -1; 00310 00311 for(x = 0; cdr_readonly_vars[x]; x++) { 00312 if (!strcasecmp(name, cdr_readonly_vars[x])) { 00313 ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!.\n", name); 00314 return -1; 00315 } 00316 } 00317 00318 if (!cdr) { 00319 ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n"); 00320 return -1; 00321 } 00322 00323 for (; cdr; cdr = recur ? cdr->next : NULL) { 00324 if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 00325 continue; 00326 headp = &cdr->varshead; 00327 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) { 00328 if (!strcasecmp(ast_var_name(newvariable), name)) { 00329 /* there is already such a variable, delete it */ 00330 AST_LIST_REMOVE_CURRENT(headp, entries); 00331 ast_var_delete(newvariable); 00332 break; 00333 } 00334 } 00335 AST_LIST_TRAVERSE_SAFE_END; 00336 00337 if (value) { 00338 newvariable = ast_var_assign(name, value); 00339 AST_LIST_INSERT_HEAD(headp, newvariable, entries); 00340 } 00341 } 00342 00343 return 0; 00344 }
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 1107 of file cdr.c.
References ast_cdr::answer, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, ast_flags::flags, and ast_cdr::start.
Referenced by ast_bridge_call().
01108 { 01109 struct ast_flags flags = { 0 }; 01110 01111 if (_flags) 01112 ast_copy_flags(&flags, _flags, AST_FLAGS_ALL); 01113 01114 /* Reset to initial state */ 01115 if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) { /* But do NOT lose the NoCDR() setting */ 01116 ast_clear_flag(cdr, AST_FLAGS_ALL); 01117 ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED); 01118 } else { 01119 ast_clear_flag(cdr, AST_FLAGS_ALL); 01120 } 01121 01122 memset(&cdr->start, 0, sizeof(cdr->start)); 01123 memset(&cdr->end, 0, sizeof(cdr->end)); 01124 memset(&cdr->answer, 0, sizeof(cdr->answer)); 01125 cdr->billsec = 0; 01126 cdr->duration = 0; 01127 ast_cdr_start(cdr); 01128 cdr->disposition = AST_CDR_NULL; 01129 }
void ast_cdr_start | ( | struct ast_cdr * | cdr | ) |
cdr | the cdr you wish to associate with the call Starts all CDR stuff necessary for monitoring a call Returns nothing |
Definition at line 692 of file cdr.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, ast_tvnow(), ast_cdr::channel, check_post(), ast_cdr::next, S_OR, and ast_cdr::start.
Referenced by __ast_request_and_dial(), ast_bridge_call(), ast_cdr_reset(), ast_cdr_specialized_reset(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().
00693 { 00694 char *chan; 00695 00696 for (; cdr; cdr = cdr->next) { 00697 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 00698 chan = S_OR(cdr->channel, "<unknown>"); 00699 check_post(cdr); 00700 cdr->start = ast_tvnow(); 00701 } 00702 } 00703 }
void ast_cdr_submit_batch | ( | int | shutdown | ) |
shutdown | Whether or not we are shutting down Blocks the asterisk shutdown procedures until the CDR data is submitted. Returns nothing |
Definition at line 1185 of file cdr.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, batch, batchscheduleronly, cdr_batch_lock, 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().
01186 { 01187 struct ast_cdr_batch_item *oldbatchitems = NULL; 01188 pthread_attr_t attr; 01189 pthread_t batch_post_thread = AST_PTHREADT_NULL; 01190 01191 /* if there's no batch, or no CDRs in the batch, then there's nothing to do */ 01192 if (!batch || !batch->head) 01193 return; 01194 01195 /* move the old CDRs aside, and prepare a new CDR batch */ 01196 ast_mutex_lock(&cdr_batch_lock); 01197 oldbatchitems = batch->head; 01198 reset_batch(); 01199 ast_mutex_unlock(&cdr_batch_lock); 01200 01201 /* if configured, spawn a new thread to post these CDRs, 01202 also try to save as much as possible if we are shutting down safely */ 01203 if (batchscheduleronly || shutdown) { 01204 if (option_debug) 01205 ast_log(LOG_DEBUG, "CDR single-threaded batch processing begins now\n"); 01206 do_batch_backend_process(oldbatchitems); 01207 } else { 01208 pthread_attr_init(&attr); 01209 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 01210 if (ast_pthread_create_background(&batch_post_thread, &attr, do_batch_backend_process, oldbatchitems)) { 01211 ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n"); 01212 do_batch_backend_process(oldbatchitems); 01213 } else { 01214 if (option_debug) 01215 ast_log(LOG_DEBUG, "CDR multi-threaded batch processing begins now\n"); 01216 } 01217 pthread_attr_destroy(&attr); 01218 } 01219 }
void ast_cdr_unregister | ( | const char * | name | ) |
unregister a CDR driver
Definition at line 151 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::list, ast_cdr_beitem::name, option_verbose, and VERBOSE_PREFIX_2.
Referenced by my_unload_module(), odbc_unload_module(), reload(), tds_unload_module(), and unload_module().
00152 { 00153 struct ast_cdr_beitem *i = NULL; 00154 00155 AST_LIST_LOCK(&be_list); 00156 AST_LIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) { 00157 if (!strcasecmp(name, i->name)) { 00158 AST_LIST_REMOVE_CURRENT(&be_list, list); 00159 if (option_verbose > 1) 00160 ast_verbose(VERBOSE_PREFIX_2 "Unregistered '%s' CDR backend\n", name); 00161 free(i); 00162 break; 00163 } 00164 } 00165 AST_LIST_TRAVERSE_SAFE_END; 00166 AST_LIST_UNLOCK(&be_list); 00167 }
int ast_cdr_update | ( | struct ast_channel * | c | ) |
Definition at line 1000 of file cdr.c.
References ast_channel::accountcode, AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, ast_channel::context, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_cdr::next, S_OR, and set_one_cid().
Referenced by __ast_pbx_run(), __ast_request_and_dial(), ast_bridge_call(), cb_events(), clear_caller(), findmeexec(), and local_call().
01001 { 01002 struct ast_cdr *cdr = c->cdr; 01003 01004 for ( ; cdr ; cdr = cdr->next) { 01005 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { 01006 set_one_cid(cdr, c); 01007 01008 /* Copy account code et-al */ 01009 ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode)); 01010 01011 /* Destination information */ /* XXX privilege macro* ? */ 01012 ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst)); 01013 ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext)); 01014 } 01015 } 01016 01017 return 0; 01018 }
static void cdr_get_tv | ( | struct timeval | tv, | |
const char * | fmt, | |||
char * | buf, | |||
int | bufsize | |||
) | [static] |
Definition at line 213 of file cdr.c.
References ast_localtime(), and t.
Referenced by ast_cdr_getvar().
00214 { 00215 if (fmt == NULL) { /* raw mode */ 00216 snprintf(buf, bufsize, "%ld.%06ld", (long)tv.tv_sec, (long)tv.tv_usec); 00217 } else { 00218 time_t t = tv.tv_sec; 00219 if (t) { 00220 struct tm tm; 00221 00222 ast_localtime(&t, &tm, NULL); 00223 strftime(buf, bufsize, fmt, &tm); 00224 } 00225 } 00226 }
Definition at line 477 of file cdr.c.
References AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_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().
00478 { 00479 struct ast_var_t *variablesfrom,*variablesto; 00480 struct varshead *headpfrom = &to->varshead; 00481 struct varshead *headpto = &from->varshead; 00482 AST_LIST_TRAVERSE_SAFE_BEGIN(headpfrom, variablesfrom, entries) { 00483 /* for every var in from, stick it in to */ 00484 const char *fromvarname = NULL, *fromvarval = NULL; 00485 const char *tovarname = NULL, *tovarval = NULL; 00486 fromvarname = ast_var_name(variablesfrom); 00487 fromvarval = ast_var_value(variablesfrom); 00488 tovarname = 0; 00489 00490 /* now, quick see if that var is in the 'to' cdr already */ 00491 AST_LIST_TRAVERSE(headpto, variablesto, entries) { 00492 00493 /* now, quick see if that var is in the 'to' cdr already */ 00494 if ( strcasecmp(fromvarname, ast_var_name(variablesto)) == 0 ) { 00495 tovarname = ast_var_name(variablesto); 00496 tovarval = ast_var_value(variablesto); 00497 break; 00498 } 00499 } 00500 if (tovarname && strcasecmp(fromvarval,tovarval) != 0) { /* this message here to see how irritating the userbase finds it */ 00501 ast_log(LOG_NOTICE, "Merging CDR's: variable %s value %s dropped in favor of value %s\n", tovarname, fromvarval, tovarval); 00502 continue; 00503 } else if (tovarname && strcasecmp(fromvarval,tovarval) == 0) /* if they are the same, the job is done */ 00504 continue; 00505 00506 /*rip this var out of the from cdr, and stick it in the to cdr */ 00507 AST_LIST_REMOVE_CURRENT(headpfrom, entries); 00508 AST_LIST_INSERT_HEAD(headpto, variablesfrom, entries); 00509 } 00510 AST_LIST_TRAVERSE_SAFE_END; 00511 }
int check_cdr_enabled | ( | void | ) |
Return TRUE if CDR subsystem is enabled.
Definition at line 105 of file cdr.c.
References enabled.
Referenced by action_coresettings(), and handle_show_settings().
00106 { 00107 return enabled; 00108 }
static void check_post | ( | struct ast_cdr * | cdr | ) | [static] |
print a warning if cdr already posted
Definition at line 430 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().
00431 { 00432 if (!cdr) 00433 return; 00434 if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED)) 00435 ast_log(LOG_NOTICE, "CDR on channel '%s' already posted\n", S_OR(cdr->channel, "<unknown>")); 00436 }
static void* do_batch_backend_process | ( | void * | data | ) | [static] |
Definition at line 1168 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().
01169 { 01170 struct ast_cdr_batch_item *processeditem; 01171 struct ast_cdr_batch_item *batchitem = data; 01172 01173 /* Push each CDR into storage mechanism(s) and free all the memory */ 01174 while (batchitem) { 01175 post_cdr(batchitem->cdr); 01176 ast_cdr_free(batchitem->cdr); 01177 processeditem = batchitem; 01178 batchitem = batchitem->next; 01179 free(processeditem); 01180 } 01181 01182 return NULL; 01183 }
static void* do_cdr | ( | void * | data | ) | [static] |
Definition at line 1298 of file cdr.c.
References ast_cond_timedwait(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_samp2tv(), ast_sched_runq(), ast_sched_wait(), ast_tvadd(), ast_tvnow(), cdr_pending_cond, cdr_pending_lock, LOG_DEBUG, and option_debug.
Referenced by do_reload().
01299 { 01300 struct timespec timeout; 01301 int schedms; 01302 int numevents = 0; 01303 01304 for(;;) { 01305 struct timeval now; 01306 schedms = ast_sched_wait(sched); 01307 /* this shouldn't happen, but provide a 1 second default just in case */ 01308 if (schedms <= 0) 01309 schedms = 1000; 01310 now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000)); 01311 timeout.tv_sec = now.tv_sec; 01312 timeout.tv_nsec = now.tv_usec * 1000; 01313 /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */ 01314 ast_mutex_lock(&cdr_pending_lock); 01315 ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout); 01316 numevents = ast_sched_runq(sched); 01317 ast_mutex_unlock(&cdr_pending_lock); 01318 if (option_debug > 1) 01319 ast_log(LOG_DEBUG, "Processed %d scheduled CDR batches from the run queue\n", numevents); 01320 } 01321 01322 return NULL; 01323 }
static int do_reload | ( | void | ) | [static] |
Definition at line 1385 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_batch_lock, cdr_pending_cond, cdr_sched, cdr_thread, cli_submit, config, do_cdr(), enabled, LOG_ERROR, LOG_NOTICE, LOG_WARNING, submit_scheduled_batch(), and unanswered.
Referenced by ast_cdr_engine_init(), ast_cdr_engine_reload(), dnsmgr_init(), dnsmgr_reload(), and handle_cli_reload().
01386 { 01387 struct ast_config *config; 01388 const char *enabled_value; 01389 const char *unanswered_value; 01390 const char *batched_value; 01391 const char *scheduleronly_value; 01392 const char *batchsafeshutdown_value; 01393 const char *size_value; 01394 const char *time_value; 01395 const char *end_before_h_value; 01396 int cfg_size; 01397 int cfg_time; 01398 int was_enabled; 01399 int was_batchmode; 01400 int res=0; 01401 01402 ast_mutex_lock(&cdr_batch_lock); 01403 01404 batchsize = BATCH_SIZE_DEFAULT; 01405 batchtime = BATCH_TIME_DEFAULT; 01406 batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT; 01407 batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT; 01408 was_enabled = enabled; 01409 was_batchmode = batchmode; 01410 enabled = 1; 01411 batchmode = 0; 01412 01413 /* don't run the next scheduled CDR posting while reloading */ 01414 AST_SCHED_DEL(sched, cdr_sched); 01415 01416 if ((config = ast_config_load("cdr.conf"))) { 01417 if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) { 01418 enabled = ast_true(enabled_value); 01419 } 01420 if ((unanswered_value = ast_variable_retrieve(config, "general", "unanswered"))) { 01421 unanswered = ast_true(unanswered_value); 01422 } 01423 if ((batched_value = ast_variable_retrieve(config, "general", "batch"))) { 01424 batchmode = ast_true(batched_value); 01425 } 01426 if ((scheduleronly_value = ast_variable_retrieve(config, "general", "scheduleronly"))) { 01427 batchscheduleronly = ast_true(scheduleronly_value); 01428 } 01429 if ((batchsafeshutdown_value = ast_variable_retrieve(config, "general", "safeshutdown"))) { 01430 batchsafeshutdown = ast_true(batchsafeshutdown_value); 01431 } 01432 if ((size_value = ast_variable_retrieve(config, "general", "size"))) { 01433 if (sscanf(size_value, "%30d", &cfg_size) < 1) 01434 ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", size_value); 01435 else if (cfg_size < 0) 01436 ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size); 01437 else 01438 batchsize = cfg_size; 01439 } 01440 if ((time_value = ast_variable_retrieve(config, "general", "time"))) { 01441 if (sscanf(time_value, "%30d", &cfg_time) < 1) 01442 ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", time_value); 01443 else if (cfg_time < 0) 01444 ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time); 01445 else 01446 batchtime = cfg_time; 01447 } 01448 if ((end_before_h_value = ast_variable_retrieve(config, "general", "endbeforehexten"))) 01449 ast_set2_flag(&ast_options, ast_true(end_before_h_value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN); 01450 } 01451 01452 if (enabled && !batchmode) { 01453 ast_log(LOG_NOTICE, "CDR simple logging enabled.\n"); 01454 } else if (enabled && batchmode) { 01455 cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL); 01456 ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime); 01457 } else { 01458 ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n"); 01459 } 01460 01461 /* if this reload enabled the CDR batch mode, create the background thread 01462 if it does not exist */ 01463 if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) { 01464 ast_cond_init(&cdr_pending_cond, NULL); 01465 if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) { 01466 ast_log(LOG_ERROR, "Unable to start CDR thread.\n"); 01467 AST_SCHED_DEL(sched, cdr_sched); 01468 } else { 01469 ast_cli_register(&cli_submit); 01470 ast_register_atexit(ast_cdr_engine_term); 01471 res = 0; 01472 } 01473 /* if this reload disabled the CDR and/or batch mode and there is a background thread, 01474 kill it */ 01475 } else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) { 01476 /* wake up the thread so it will exit */ 01477 pthread_cancel(cdr_thread); 01478 pthread_kill(cdr_thread, SIGURG); 01479 pthread_join(cdr_thread, NULL); 01480 cdr_thread = AST_PTHREADT_NULL; 01481 ast_cond_destroy(&cdr_pending_cond); 01482 ast_cli_unregister(&cli_submit); 01483 ast_unregister_atexit(ast_cdr_engine_term); 01484 res = 0; 01485 /* if leaving batch mode, then post the CDRs in the batch, 01486 and don't reschedule, since we are stopping CDR logging */ 01487 if (!batchmode && was_batchmode) { 01488 ast_cdr_engine_term(); 01489 } 01490 } else { 01491 res = 0; 01492 } 01493 01494 ast_mutex_unlock(&cdr_batch_lock); 01495 ast_config_destroy(config); 01496 01497 return res; 01498 }
static int handle_cli_status | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1325 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, ast_cdr_beitem::list, ast_cdr_beitem::name, RESULT_SHOWUSAGE, and unanswered.
01326 { 01327 struct ast_cdr_beitem *beitem=NULL; 01328 int cnt=0; 01329 long nextbatchtime=0; 01330 01331 if (argc > 2) 01332 return RESULT_SHOWUSAGE; 01333 01334 ast_cli(fd, "CDR logging: %s\n", enabled ? "enabled" : "disabled"); 01335 ast_cli(fd, "CDR mode: %s\n", batchmode ? "batch" : "simple"); 01336 if (enabled) { 01337 ast_cli(fd, "CDR output unanswered calls: %s\n", unanswered ? "yes" : "no"); 01338 if (batchmode) { 01339 if (batch) 01340 cnt = batch->size; 01341 if (cdr_sched > -1) 01342 nextbatchtime = ast_sched_when(sched, cdr_sched); 01343 ast_cli(fd, "CDR safe shut down: %s\n", batchsafeshutdown ? "enabled" : "disabled"); 01344 ast_cli(fd, "CDR batch threading model: %s\n", batchscheduleronly ? "scheduler only" : "scheduler plus separate threads"); 01345 ast_cli(fd, "CDR current batch size: %d record%s\n", cnt, (cnt != 1) ? "s" : ""); 01346 ast_cli(fd, "CDR maximum batch size: %d record%s\n", batchsize, (batchsize != 1) ? "s" : ""); 01347 ast_cli(fd, "CDR maximum batch time: %d second%s\n", batchtime, (batchtime != 1) ? "s" : ""); 01348 ast_cli(fd, "CDR next scheduled batch processing time: %ld second%s\n", nextbatchtime, (nextbatchtime != 1) ? "s" : ""); 01349 } 01350 AST_LIST_LOCK(&be_list); 01351 AST_LIST_TRAVERSE(&be_list, beitem, list) { 01352 ast_cli(fd, "CDR registered backend: %s\n", beitem->name); 01353 } 01354 AST_LIST_UNLOCK(&be_list); 01355 } 01356 01357 return 0; 01358 }
static int handle_cli_submit | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1360 of file cdr.c.
References ast_cli(), RESULT_SHOWUSAGE, and submit_unscheduled_batch().
01361 { 01362 if (argc > 2) 01363 return RESULT_SHOWUSAGE; 01364 01365 submit_unscheduled_batch(); 01366 ast_cli(fd, "Submitted CDRs to backend engines for processing. This may take a while.\n"); 01367 01368 return 0; 01369 }
static int init_batch | ( | void | ) | [static] |
Definition at line 1157 of file cdr.c.
References ast_malloc, batch, and reset_batch().
Referenced by ast_cdr_detach(), and ast_cdr_engine_init().
01158 { 01159 /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */ 01160 if (!(batch = ast_malloc(sizeof(*batch)))) 01161 return -1; 01162 01163 reset_batch(); 01164 01165 return 0; 01166 }
static void post_cdr | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 1033 of file cdr.c.
References AST_CDR_ANSWERED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_ORIGINATED, AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_tvzero(), ast_verbose(), ast_cdr_beitem::be, ast_cdr::channel, check_post(), ast_cdr::disposition, ast_cdr::dstchannel, ast_cdr::end, ast_cdr_beitem::list, ast_cdr::next, option_verbose, S_OR, ast_cdr::start, unanswered, and VERBOSE_PREFIX_2.
Referenced by ast_cdr_detach(), and do_batch_backend_process().
01034 { 01035 char *chan; 01036 struct ast_cdr_beitem *i; 01037 01038 for ( ; cdr ; cdr = cdr->next) { 01039 if (!unanswered && !ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) { 01040 /* For people, who don't want to see unanswered single-channel events */ 01041 ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED); 01042 continue; 01043 } 01044 01045 /* don't post CDRs that are for dialed channels unless those 01046 * channels were originated from asterisk (pbx_spool, manager, 01047 * cli) */ 01048 if (ast_test_flag(cdr, AST_CDR_FLAG_DIALED) && !ast_test_flag(cdr, AST_CDR_FLAG_ORIGINATED)) { 01049 ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED); 01050 continue; 01051 } 01052 01053 chan = S_OR(cdr->channel, "<unknown>"); 01054 check_post(cdr); 01055 if (option_verbose > 1 && ast_tvzero(cdr->end)) 01056 ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' lacks end\n", chan); 01057 if (option_verbose > 1 && ast_tvzero(cdr->start)) 01058 ast_verbose(VERBOSE_PREFIX_2 "CDR on channel '%s' lacks start\n", chan); 01059 ast_set_flag(cdr, AST_CDR_FLAG_POSTED); 01060 if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) 01061 continue; 01062 AST_LIST_LOCK(&be_list); 01063 AST_LIST_TRAVERSE(&be_list, i, list) { 01064 i->be(cdr); 01065 } 01066 AST_LIST_UNLOCK(&be_list); 01067 } 01068 }
static void reset_batch | ( | void | ) | [static] |
Definition at line 1149 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().
static void set_one_cid | ( | struct ast_cdr * | cdr, | |
struct ast_channel * | c | |||
) | [static] |
Definition at line 828 of file cdr.c.
References ast_cdr_setvar(), ast_copy_string(), ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_dnid, 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().
00829 { 00830 /* Grab source from ANI or normal Caller*ID */ 00831 const char *num = S_OR(c->cid.cid_ani, c->cid.cid_num); 00832 if (!cdr) 00833 return; 00834 if (!ast_strlen_zero(c->cid.cid_name)) { 00835 if (!ast_strlen_zero(num)) /* both name and number */ 00836 snprintf(cdr->clid, sizeof(cdr->clid), "\"%s\" <%s>", c->cid.cid_name, num); 00837 else /* only name */ 00838 ast_copy_string(cdr->clid, c->cid.cid_name, sizeof(cdr->clid)); 00839 } else if (!ast_strlen_zero(num)) { /* only number */ 00840 ast_copy_string(cdr->clid, num, sizeof(cdr->clid)); 00841 } else { /* nothing known */ 00842 cdr->clid[0] = '\0'; 00843 } 00844 ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src)); 00845 ast_cdr_setvar(cdr, "dnid", S_OR(c->cid.cid_dnid, ""), 0); 00846 00847 }
static int submit_scheduled_batch | ( | const void * | data | ) | [static] |
Definition at line 1221 of file cdr.c.
References ast_cdr_submit_batch(), ast_sched_add(), batchtime, and cdr_sched.
Referenced by do_reload(), and submit_unscheduled_batch().
01222 { 01223 ast_cdr_submit_batch(0); 01224 /* manually reschedule from this point in time */ 01225 cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL); 01226 /* returning zero so the scheduler does not automatically reschedule */ 01227 return 0; 01228 }
static void submit_unscheduled_batch | ( | void | ) | [static] |
Definition at line 1230 of file cdr.c.
References ast_cond_signal(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_add(), AST_SCHED_DEL, cdr_pending_cond, cdr_pending_lock, cdr_sched, and submit_scheduled_batch().
Referenced by ast_cdr_detach(), and handle_cli_submit().
01231 { 01232 /* this is okay since we are not being called from within the scheduler */ 01233 AST_SCHED_DEL(sched, cdr_sched); 01234 /* schedule the submission to occur ASAP (1 ms) */ 01235 cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL); 01236 /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */ 01237 ast_mutex_lock(&cdr_pending_lock); 01238 ast_cond_signal(&cdr_pending_cond); 01239 ast_mutex_unlock(&cdr_pending_lock); 01240 }
char ast_default_accountcode[AST_MAX_ACCOUNT_CODE] |
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_bridge_call().
struct ast_cdr_batch * batch [static] |
Referenced by ast_cdr_detach(), ast_cdr_submit_batch(), handle_cli_status(), init_batch(), and reset_batch().
int batchmode [static] |
Definition at line 93 of file cdr.c.
Referenced by ast_cdr_detach(), do_reload(), and handle_cli_status().
int batchsafeshutdown [static] |
Definition at line 97 of file cdr.c.
Referenced by ast_cdr_engine_term(), do_reload(), and handle_cli_status().
int batchscheduleronly [static] |
Definition at line 96 of file cdr.c.
Referenced by ast_cdr_submit_batch(), do_reload(), and handle_cli_status().
int batchsize [static] |
Definition at line 94 of file cdr.c.
Referenced by ast_cdr_detach(), do_reload(), and handle_cli_status().
int batchtime [static] |
Definition at line 95 of file cdr.c.
Referenced by do_reload(), handle_cli_status(), and submit_scheduled_batch().
ast_mutex_t cdr_batch_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static] |
Definition at line 99 of file cdr.c.
Referenced by ast_cdr_detach(), ast_cdr_engine_init(), ast_cdr_submit_batch(), and do_reload().
ast_cond_t cdr_pending_cond [static] |
Definition at line 103 of file cdr.c.
Referenced by do_cdr(), do_reload(), and submit_unscheduled_batch().
ast_mutex_t cdr_pending_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static] |
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 295 of file cdr.c.
Referenced by ast_cdr_serialize_variables(), and ast_cdr_setvar().
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] |
struct ast_cli_entry cli_status [static] |
struct ast_cli_entry cli_submit [static] |
int enabled [static] |
Definition at line 91 of file cdr.c.
Referenced by __ast_http_load(), ast_cdr_detach(), ast_dnsmgr_lookup(), check_cdr_enabled(), do_reload(), handle_cli_refresh(), handle_cli_status(), load_odbc_config(), osp_check_destination(), and reload().
struct sched_context* sched [static] |
Definition at line 82 of file cdr.c.
Referenced by __attempt_transmit(), __find_callno(), __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(), ast_udptl_new_with_bindaddr(), auth_fail(), build_peer(), delete_users(), destroy_packet(), destroy_packets(), destroy_peer(), dnsmgr_init(), dnsmgr_start_refresh(), do_monitor(), do_refresh(), do_register(), do_reload(), dundi_discover(), dundi_query(), dundi_send(), handle_command_response(), handle_request_cancel(), handle_response_invite(), handle_response_peerpoke(), handle_response_register(), iax2_ack_registry(), iax2_call(), iax2_destroy(), iax2_destroy_helper(), iax2_do_register(), iax2_dprequest(), iax2_frame_free(), iax2_hangup(), iax2_poke_peer(), iax2_provision(), load_module(), make_trunk(), network_thread(), parse_register_contact(), populate_addr(), precache_trans(), qualify_peer(), queue_request(), reg_source_db(), remove_provisional_keepalive_sched(), sched_delay_remove(), sched_thread(), schedule_delivery(), sip_alloc(), sip_call(), sip_cancel_destroy(), sip_do_reload(), sip_hangup(), sip_poke_all_peers(), sip_poke_noanswer(), sip_poke_peer(), sip_registry_destroy(), sip_scheddestroy(), sip_send_all_registers(), sipsock_read(), socket_process(), transmit_register(), unlink_peer(), unload_module(), update_jbsched(), update_provisional_keepalive(), and update_registry().
int unanswered [static] |
Is the CDR subsystem enabled ?
Definition at line 92 of file cdr.c.
Referenced by ast_cdr_isset_unanswered(), do_reload(), handle_cli_status(), and post_cdr().