204 #define DEFAULT_ENABLED "1"
205 #define DEFAULT_BATCHMODE "0"
206 #define DEFAULT_UNANSWERED "0"
207 #define DEFAULT_CONGESTION "0"
208 #define DEFAULT_END_BEFORE_H_EXTEN "1"
209 #define DEFAULT_INITIATED_SECONDS "0"
210 #define DEFAULT_CHANNEL_ENABLED "1"
212 #define DEFAULT_BATCH_SIZE "100"
213 #define MAX_BATCH_SIZE 1000
214 #define DEFAULT_BATCH_TIME "300"
215 #define MAX_BATCH_TIME 86400
216 #define DEFAULT_BATCH_SCHEDULER_ONLY "0"
217 #define DEFAULT_BATCH_SAFE_SHUTDOWN "1"
219 #define cdr_set_debug_mode(mod_cfg) \
221 cdr_debug_enabled = ast_test_flag(&(mod_cfg)->general->settings, CDR_DEBUG); \
226 #define CDR_DEBUG(fmt, ...) \
228 if (cdr_debug_enabled) { \
229 ast_verbose((fmt), ##__VA_ARGS__); \
250 .category =
"general",
499 const char *dial_status);
654 .
name =
"DialedPending",
734 struct timeval
start;
823 CDR_DEBUG(
"%p - Transitioning CDR for %s from state %s to %s\n",
875 const char *right_key = arg;
883 cmp = strcmp(left->
uniqueid, right_key);
890 cmp = strncmp(left->
uniqueid, right_key, strlen(right_key));
933 const char *right_key = arg;
948 cmp = strncasecmp(left->
party_b_name, right_key, strlen(right_key));
995 for (cur = cdr; cur; cur =
next) {
1096 cdr_last = cdr->
last;
1122 for (it_cdr = cdr; it_cdr->
next; it_cdr = it_cdr->
next) {
1123 it_cdr->
last = new_cdr;
1125 it_cdr->
last = new_cdr;
1126 it_cdr->
next = new_cdr;
1175 && strncasecmp(new_snapshot->
dialplan->
appl,
"appdial", 7)
1257 if (ms % 1000 >= 500
1259 ms = (ms / 1000) + 1;
1308 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
1313 ast_debug(1,
"CDR for %s is dialed and has no Party B; discarding\n",
1355 cdr_copy->
end = it_cdr->
end;
1385 cdr_prev->
next = cdr_copy;
1386 cdr_prev = cdr_copy;
1403 CDR_DEBUG(
"%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
1418 switch (hangupcause) {
1473 ast_debug(1,
"Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dur %.3f bill %.3f dispo %s\n",
1475 (
long)cdr->
start.tv_sec,
1476 (
long)cdr->
start.tv_usec,
1477 (
long)cdr->
answer.tv_sec,
1478 (
long)cdr->
answer.tv_usec,
1479 (
long)cdr->
end.tv_sec,
1480 (
long)cdr->
end.tv_usec,
1512 CDR_DEBUG(
"%p - Set answered time to %ld.%06ld\n", cdr,
1513 (
long)cdr->
answer.tv_sec,
1514 (
long)cdr->
answer.tv_usec);
1632 char park_info[128];
1670 CDR_DEBUG(
"%p - Updated Party A %s snapshot\n", cdr,
1674 CDR_DEBUG(
"%p - Updated Party B %s snapshot\n", cdr,
1685 CDR_DEBUG(
"%p - Updated Party A %s snapshot\n", cdr,
1718 CDR_DEBUG(
"%p - Party A %s has new Party B %s\n",
1739 CDR_DEBUG(
"%p - Party A %s has new Party B %s\n",
1770 if (!cand_cdr_master) {
1775 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->
next) {
1843 if (!strcmp(dial_status,
"ANSWER")) {
1845 }
else if (!strcmp(dial_status,
"BUSY")) {
1847 }
else if (!strcmp(dial_status,
"CANCEL") || !strcmp(dial_status,
"NOANSWER")) {
1849 }
else if (!strcmp(dial_status,
"CONGESTION")) {
1855 }
else if (!strcmp(dial_status,
"FAILED")) {
1918 if (!cand_cdr_master) {
1923 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->
next) {
2104 return (strcmp(dialstatus,
"RINGING") &&
2105 strcmp(dialstatus,
"PROCEEDING") &&
2106 strcmp(dialstatus,
"PROGRESS"));
2125 const char *dial_status =
NULL;
2130 if (!peer && !caller) {
2143 if (dial_status_blob) {
2147 CDR_DEBUG(
"Dial %s message for %s, %s: %u.%08u\n",
2149 caller ? caller->
base->
name :
"(none)",
2150 peer ? peer->
base->
name :
"(none)",
2167 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2173 CDR_DEBUG(
"%p - Processing Dial Begin message for channel %s, peer %s\n",
2175 caller ? caller->
base->
name :
"(none)",
2176 peer ? peer->
base->
name :
"(none)");
2184 CDR_DEBUG(
"%p - Processing Dial End message for channel %s, peer %s\n",
2186 caller ? caller->
base->
name :
"(none)",
2187 peer ? peer->
base->
name :
"(none)");
2248 "CDR for Party A %s(%s) has inconsistent Party B %s name. Message can be ignored but this shouldn't happen.\n",
2314 ast_debug(3,
"Disable CDR by default\n");
2331 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2352 CDR_DEBUG(
"%p - Beginning finalize/dispatch for %s\n", cdr,
update->old_snapshot->base->name);
2353 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2365 if (
update->new_snapshot) {
2440 int left_bridge = 0;
2450 CDR_DEBUG(
"Bridge Leave message for %s: %u.%08u\n",
2452 (
unsigned int)leave_data.
lastevent->tv_sec,
2453 (
unsigned int)leave_data.
lastevent->tv_usec);
2464 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2469 CDR_DEBUG(
"%p - Processing Bridge Leave for %s\n",
2509 CDR_DEBUG(
"%p - Party A %s has new Party B %s\n",
2533 for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->
next) {
2560 CDR_DEBUG(
"%p - Party A %s has new Party B %s\n",
2569 memset(&cand_cdr->
end, 0,
sizeof(cand_cdr->
end));
2613 const struct timeval *event_time)
2621 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2628 CDR_DEBUG(
"%p - Updating Party A %s snapshot\n", it_cdr,
2655 const struct timeval *event_time)
2665 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2669 CDR_DEBUG(
"%p - Updating Party A %s snapshot\n", it_cdr,
2676 CDR_DEBUG(
"%p - Processing bridge enter for %s\n", it_cdr,
2684 handled_cdr = it_cdr;
2695 handled_cdr = it_cdr;
2748 CDR_DEBUG(
"Bridge Enter message for channel %s: %u.%08u\n",
2760 if (!strcmp(
bridge->subclass,
"parking")) {
2797 CDR_DEBUG(
"Parked Call message for channel %s: %u.%08u\n",
2811 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2950 if (!strcasecmp(
name, cur->
name)) {
2994 if (!
match->suspended && active_count != 0) {
2997 name, active_count);
3057 static void cdr_get_tv(
struct timeval when,
const char *fmt,
char *
buf,
int bufsize)
3060 snprintf(
buf, bufsize,
"%ld.%06ld", (
long)when.tv_sec, (
long)when.tv_usec);
3074 const char *fmt =
"%Y-%m-%d %T";
3083 if (!strcasecmp(
name,
"clid")) {
3085 }
else if (!strcasecmp(
name,
"src")) {
3087 }
else if (!strcasecmp(
name,
"dst")) {
3089 }
else if (!strcasecmp(
name,
"dcontext")) {
3091 }
else if (!strcasecmp(
name,
"channel")) {
3093 }
else if (!strcasecmp(
name,
"dstchannel")) {
3095 }
else if (!strcasecmp(
name,
"lastapp")) {
3097 }
else if (!strcasecmp(
name,
"lastdata")) {
3099 }
else if (!strcasecmp(
name,
"start")) {
3101 }
else if (!strcasecmp(
name,
"answer")) {
3103 }
else if (!strcasecmp(
name,
"end")) {
3105 }
else if (!strcasecmp(
name,
"duration")) {
3107 }
else if (!strcasecmp(
name,
"billsec")) {
3109 }
else if (!strcasecmp(
name,
"disposition")) {
3111 snprintf(workspace, workspacelen,
"%ld", cdr->
disposition);
3115 }
else if (!strcasecmp(
name,
"amaflags")) {
3117 snprintf(workspace, workspacelen,
"%ld", cdr->
amaflags);
3121 }
else if (!strcasecmp(
name,
"accountcode")) {
3123 }
else if (!strcasecmp(
name,
"peeraccount")) {
3125 }
else if (!strcasecmp(
name,
"uniqueid")) {
3127 }
else if (!strcasecmp(
name,
"linkedid")) {
3129 }
else if (!strcasecmp(
name,
"userfield")) {
3131 }
else if (!strcasecmp(
name,
"sequence")) {
3132 snprintf(workspace, workspacelen,
"%d", cdr->
sequence);
3136 workspace[0] =
'\0';
3151 const char *
name = arg;
3167 const char *
name = arg;
3223 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3270 if (!strcasecmp(
name,
"clid")) {
3272 }
else if (!strcasecmp(
name,
"src")) {
3274 }
else if (!strcasecmp(
name,
"dst")) {
3276 }
else if (!strcasecmp(
name,
"dcontext")) {
3278 }
else if (!strcasecmp(
name,
"channel")) {
3280 }
else if (!strcasecmp(
name,
"dstchannel")) {
3286 }
else if (!strcasecmp(
name,
"lastapp")) {
3288 }
else if (!strcasecmp(
name,
"lastdata")) {
3290 }
else if (!strcasecmp(
name,
"start")) {
3292 }
else if (!strcasecmp(
name,
"answer")) {
3294 }
else if (!strcasecmp(
name,
"end")) {
3296 }
else if (!strcasecmp(
name,
"duration")) {
3298 }
else if (!strcasecmp(
name,
"billsec")) {
3300 }
else if (!strcasecmp(
name,
"disposition")) {
3302 }
else if (!strcasecmp(
name,
"amaflags")) {
3304 }
else if (!strcasecmp(
name,
"accountcode")) {
3306 }
else if (!strcasecmp(
name,
"peeraccount")) {
3312 }
else if (!strcasecmp(
name,
"uniqueid")) {
3314 }
else if (!strcasecmp(
name,
"linkedid")) {
3316 }
else if (!strcasecmp(
name,
"userfield")) {
3318 }
else if (!strcasecmp(
name,
"sequence")) {
3363 cdr_obj = cdr->
last;
3381 char workspace[256];
3382 int total = 0, x = 0, i;
3395 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3466 return "CONGESTION";
3512 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3540 for (; cdr ; cdr = cdr->
next) {
3545 ast_debug(1,
"Skipping CDR for %s since we weren't answered\n", cdr->
channel);
3561 if (!i->suspended) {
3581 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3608 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3632 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3634 if (!keep_variables) {
3646 memset(&it_cdr->
start, 0,
sizeof(it_cdr->
start));
3647 memset(&it_cdr->
end, 0,
sizeof(it_cdr->
end));
3674 cdr_obj = cdr->
last;
3735 for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->
next) {
3780 processeditem = batchitem;
3781 batchitem = batchitem->
next;
3812 ast_debug(1,
"CDR single-threaded batch processing begins now\n");
3816 ast_log(
LOG_WARNING,
"CDR processing thread could not detach, now trying in this thread\n");
3819 ast_debug(1,
"CDR multi-threaded batch processing begins now\n");
3868 int submit_batch = 0;
3889 ast_debug(1,
"CDR detaching from this thread\n");
3892 if (!(newtail =
ast_calloc(1,
sizeof(*newtail)))) {
3914 if (curr >= (mod_cfg->general->batch_settings.size - 1)) {
3927 struct timespec timeout;
3938 timeout.tv_sec = now.tv_sec;
3939 timeout.tv_nsec = now.tv_usec * 1000;
3945 ast_debug(2,
"Processed %d CDR batches from the run queue\n", numevents);
3957 e->
command =
"cdr set debug [on|off]";
3958 e->
usage =
"Enable or disable extra debugging in the CDR Engine. Note\n"
3959 "that this will dump debug information to the VERBOSE setting\n"
3960 "and should only be used when debugging information from the\n"
3961 "CDR engine is needed.\n";
3973 ast_cli(
a->fd,
"Could not set CDR debugging mode\n");
3976 if (!strcasecmp(
a->argv[3],
"on")
3979 ast_cli(
a->fd,
"CDR debugging enabled\n");
3980 }
else if (!strcasecmp(
a->argv[3],
"off")
3983 ast_cli(
a->fd,
"CDR debugging disabled\n");
3994 int wordlen = strlen(
a->word);
4017 char start_time_buffer[64];
4018 char answer_time_buffer[64];
4019 char end_time_buffer[64];
4021 #define TITLE_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4022 #define FORMAT_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4025 ast_cli(
a->fd,
"Channels with Call Detail Record (CDR) Information\n");
4026 ast_cli(
a->fd,
"--------------------------------------------------\n");
4027 ast_cli(
a->fd,
TITLE_STRING,
"Channel",
"Dst. Channel",
"LastApp",
"Start",
"Answer",
"End",
"Billsec",
"Duration");
4032 struct timeval start_time = { 0, };
4033 struct timeval answer_time = { 0, };
4034 struct timeval end_time = { 0, };
4041 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
4046 start_time = it_cdr->
start;
4049 answer_time = it_cdr->
answer;
4060 cdr_get_tv(start_time,
"%T", start_time_buffer,
sizeof(start_time_buffer));
4061 cdr_get_tv(answer_time,
"%T", answer_time_buffer,
sizeof(answer_time_buffer));
4062 cdr_get_tv(end_time,
"%T", end_time_buffer,
sizeof(end_time_buffer));
4073 #undef FORMAT_STRING
4081 char start_time_buffer[64];
4082 char answer_time_buffer[64];
4083 char end_time_buffer[64];
4084 const char *channel_name =
a->argv[3];
4087 #define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4088 #define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4092 ast_cli(
a->fd,
"Unknown channel: %s\n", channel_name);
4097 ast_cli(
a->fd,
"Call Detail Record (CDR) Information for %s\n", channel_name);
4098 ast_cli(
a->fd,
"--------------------------------------------------\n");
4099 ast_cli(
a->fd,
TITLE_STRING,
"AccountCode",
"CallerID",
"Dst. Channel",
"LastApp",
"Data",
"Start",
"Answer",
"End",
"Billsec",
"Duration");
4102 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
4114 cdr_get_tv(it_cdr->
start,
"%T", start_time_buffer,
sizeof(start_time_buffer));
4115 cdr_get_tv(it_cdr->
answer,
"%T", answer_time_buffer,
sizeof(answer_time_buffer));
4116 cdr_get_tv(
end,
"%T", end_time_buffer,
sizeof(end_time_buffer));
4133 #undef FORMAT_STRING
4141 e->
command =
"cdr show active";
4143 "Usage: cdr show active [channel]\n"
4144 " Displays a summary of all Call Detail Records when [channel]\n"
4145 " is omitted; displays all of the Call Detail Records\n"
4146 " currently in flight for a given [channel] when [channel] is\n"
4148 " Note that this will not display Call Detail Records that\n"
4149 " have already been dispatched to a backend storage, nor for\n"
4150 " channels that are no longer active.\n";
4158 }
else if (
a->argc < 4) {
4172 long nextbatchtime = 0;
4176 e->
command =
"cdr show status";
4178 "Usage: cdr show status\n"
4179 " Displays the Call Detail Record engine system status.\n";
4195 ast_cli(
a->fd,
"Call Detail Record (CDR) settings\n");
4196 ast_cli(
a->fd,
"----------------------------------\n");
4204 ast_cli(
a->fd,
"* Batch Mode Settings\n");
4205 ast_cli(
a->fd,
" -------------------\n");
4212 ast_cli(
a->fd,
" Current batch size: %d record%s\n", cnt,
ESS(cnt));
4215 ast_cli(
a->fd,
" Next batch processing time: %ld second%s\n\n", nextbatchtime,
ESS(nextbatchtime));
4217 ast_cli(
a->fd,
"* Registered Backends\n");
4218 ast_cli(
a->fd,
" -------------------\n");
4224 ast_cli(
a->fd,
" %s%s\n", beitem->
name, beitem->suspended ?
" (suspended) " :
"");
4243 "Usage: cdr submit\n"
4244 "Posts all pending batched CDR data to the configured CDR\n"
4245 "backend engine modules.\n";
4260 ast_cli(
a->fd,
"Cannot submit CDR batch: CDR engine disabled.\n");
4262 ast_cli(
a->fd,
"Cannot submit CDR batch: batch mode not enabled.\n");
4265 ast_cli(
a->fd,
"Submitted CDRs to backend engines for processing. This may take a while.\n");
4289 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
4379 aco_option_register(&cfg_info,
"size",
ACO_EXACT,
general_options,
DEFAULT_BATCH_SIZE,
OPT_UINT_T,
PARSE_IN_RANGE,
FLDSET(
struct ast_cdr_config, batch_settings.size), 0,
MAX_BATCH_SIZE);
4380 aco_option_register(&cfg_info,
"time",
ACO_EXACT,
general_options,
DEFAULT_BATCH_TIME,
OPT_UINT_T,
PARSE_IN_RANGE,
FLDSET(
struct ast_cdr_config, batch_settings.time), 1,
MAX_BATCH_TIME);
4454 ast_log(
LOG_NOTICE,
"CDR batch mode logging enabled, first of either size %u or time %u seconds.\n",
4455 config->batch_settings.size,
config->batch_settings.time);
4475 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
4476 prnt(where,
"Party A: %s; Party B: %s; Bridge %s\n",
4499 prnt(where,
"Party A: %s; Party B: %s; Bridge %s",
4532 return mod_cfg ? 0 : -1;