227#define DEFAULT_ENABLED "1"
228#define DEFAULT_BATCHMODE "0"
229#define DEFAULT_UNANSWERED "0"
230#define DEFAULT_CONGESTION "0"
231#define DEFAULT_END_BEFORE_H_EXTEN "1"
232#define DEFAULT_INITIATED_SECONDS "0"
233#define DEFAULT_CHANNEL_ENABLED "1"
234#define DEFAULT_IGNORE_STATE_CHANGES "0"
235#define DEFAULT_IGNORE_DIAL_CHANGES "0"
237#define DEFAULT_BATCH_SIZE "100"
238#define MAX_BATCH_SIZE 1000
239#define DEFAULT_BATCH_TIME "300"
240#define MAX_BATCH_TIME 86400
241#define DEFAULT_BATCH_SCHEDULER_ONLY "0"
242#define DEFAULT_BATCH_SAFE_SHUTDOWN "1"
244#define cdr_set_debug_mode(mod_cfg) \
246 cdr_debug_enabled = ast_test_flag(&(mod_cfg)->general->settings, CDR_DEBUG); \
252#define CDR_DEBUG(fmt, ...) \
254 if (cdr_debug_enabled) { \
255 ast_verbose((fmt), ##__VA_ARGS__); \
276 .category =
"general",
525 const char *dial_status);
680 .
name =
"DialedPending",
850 CDR_DEBUG(
"%p - Transitioning CDR for %s from state %s to %s\n",
902 const char *right_key = arg;
910 cmp = strcmp(left->
uniqueid, right_key);
917 cmp = strncmp(left->
uniqueid, right_key, strlen(right_key));
960 const char *right_key = arg;
975 cmp = strncasecmp(left->
party_b_name, right_key, strlen(right_key));
1022 for (cur = cdr; cur; cur =
next) {
1124 cdr_last = cdr->
last;
1150 for (it_cdr = cdr; it_cdr->
next; it_cdr = it_cdr->
next) {
1151 it_cdr->
last = new_cdr;
1153 it_cdr->
last = new_cdr;
1154 it_cdr->
next = new_cdr;
1203 && strncasecmp(new_snapshot->
dialplan->
appl,
"appdial", 7)
1285 if (ms % 1000 >= 500
1287 ms = (ms / 1000) + 1;
1336 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
1341 ast_debug(1,
"CDR for %s is dialed and has no Party B; discarding\n",
1385 cdr_copy->
end = it_cdr->
end;
1415 cdr_prev->
next = cdr_copy;
1416 cdr_prev = cdr_copy;
1433 CDR_DEBUG(
"%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
1448 switch (hangupcause) {
1503 ast_debug(1,
"Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dur %.3f bill %.3f dispo %s\n",
1505 (
long)cdr->
start.tv_sec,
1506 (
long)cdr->
start.tv_usec,
1507 (
long)cdr->
answer.tv_sec,
1508 (
long)cdr->
answer.tv_usec,
1509 (
long)cdr->
end.tv_sec,
1510 (
long)cdr->
end.tv_usec,
1542 CDR_DEBUG(
"%p - Set answered time to %ld.%06ld\n", cdr,
1543 (
long)cdr->
answer.tv_sec,
1544 (
long)cdr->
answer.tv_usec);
1662 char park_info[128];
1700 CDR_DEBUG(
"%p - Updated Party A %s snapshot\n", cdr,
1704 CDR_DEBUG(
"%p - Updated Party B %s snapshot\n", cdr,
1715 CDR_DEBUG(
"%p - Updated Party A %s snapshot\n", cdr,
1748 CDR_DEBUG(
"%p - Party A %s has new Party B %s\n",
1769 CDR_DEBUG(
"%p - Party A %s has new Party B %s\n",
1800 if (!cand_cdr_master) {
1805 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->
next) {
1873 if (!strcmp(dial_status,
"ANSWER")) {
1875 }
else if (!strcmp(dial_status,
"BUSY")) {
1877 }
else if (!strcmp(dial_status,
"CANCEL") || !strcmp(dial_status,
"NOANSWER")) {
1879 }
else if (!strcmp(dial_status,
"CONGESTION")) {
1885 }
else if (!strcmp(dial_status,
"FAILED")) {
1948 if (!cand_cdr_master) {
1953 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->
next) {
2134 return (strcmp(dialstatus,
"RINGING") &&
2135 strcmp(dialstatus,
"PROCEEDING") &&
2136 strcmp(dialstatus,
"PROGRESS"));
2155 const char *dial_status =
NULL;
2160 if (!peer && !caller) {
2173 if (dial_status_blob) {
2177 CDR_DEBUG(
"Dial %s message for %s, %s: %u.%08u\n",
2179 caller ? caller->
base->
name :
"(none)",
2180 peer ? peer->
base->
name :
"(none)",
2197 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2204 CDR_DEBUG(
"%p - Ignoring Dial Begin message\n", it_cdr);
2207 CDR_DEBUG(
"%p - Processing Dial Begin message for channel %s, peer %s\n",
2209 caller ? caller->
base->
name :
"(none)",
2210 peer ? peer->
base->
name :
"(none)");
2221 CDR_DEBUG(
"%p - Setting disposition and that's it (%s)\n", it_cdr, dial_status);
2224 CDR_DEBUG(
"%p - Processing Dial End message for channel %s, peer %s\n",
2226 caller ? caller->
base->
name :
"(none)",
2227 peer ? peer->
base->
name :
"(none)");
2292 "CDR for Party A %s(%s) has inconsistent Party B %s name. Message can be ignored but this shouldn't happen.\n",
2358 ast_debug(3,
"Disable CDR by default\n");
2375 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2396 CDR_DEBUG(
"%p - Beginning finalize/dispatch for %s\n", cdr,
update->old_snapshot->base->name);
2397 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2409 if (
update->new_snapshot) {
2484 int left_bridge = 0;
2494 CDR_DEBUG(
"Bridge Leave message for %s: %u.%08u\n",
2496 (
unsigned int)leave_data.
lastevent->tv_sec,
2497 (
unsigned int)leave_data.
lastevent->tv_usec);
2508 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2513 CDR_DEBUG(
"%p - Processing Bridge Leave for %s\n",
2553 CDR_DEBUG(
"%p - Party A %s has new Party B %s\n",
2577 for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->
next) {
2604 CDR_DEBUG(
"%p - Party A %s has new Party B %s\n",
2613 memset(&cand_cdr->
end, 0,
sizeof(cand_cdr->
end));
2657 const struct timeval *event_time)
2665 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2672 CDR_DEBUG(
"%p - Updating Party A %s snapshot\n", it_cdr,
2699 const struct timeval *event_time)
2709 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2713 CDR_DEBUG(
"%p - Updating Party A %s snapshot\n", it_cdr,
2720 CDR_DEBUG(
"%p - Processing bridge enter for %s\n", it_cdr,
2728 handled_cdr = it_cdr;
2739 handled_cdr = it_cdr;
2792 CDR_DEBUG(
"Bridge Enter message for channel %s: %u.%08u\n",
2804 if (!strcmp(
bridge->subclass,
"parking")) {
2841 CDR_DEBUG(
"Parked Call message for channel %s: %u.%08u\n",
2855 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
2994 if (!strcasecmp(
name, cur->
name)) {
3038 if (!
match->suspended && active_count != 0) {
3041 name, active_count);
3101static void cdr_get_tv(
struct timeval when,
const char *fmt,
char *
buf,
int bufsize)
3104 snprintf(
buf, bufsize,
"%ld.%06ld", (
long)when.tv_sec, (
long)when.tv_usec);
3118 const char *fmt =
"%Y-%m-%d %T";
3127 if (!strcasecmp(
name,
"clid")) {
3129 }
else if (!strcasecmp(
name,
"src")) {
3131 }
else if (!strcasecmp(
name,
"dst")) {
3133 }
else if (!strcasecmp(
name,
"dcontext")) {
3135 }
else if (!strcasecmp(
name,
"channel")) {
3137 }
else if (!strcasecmp(
name,
"dstchannel")) {
3139 }
else if (!strcasecmp(
name,
"lastapp")) {
3141 }
else if (!strcasecmp(
name,
"lastdata")) {
3143 }
else if (!strcasecmp(
name,
"start")) {
3145 }
else if (!strcasecmp(
name,
"answer")) {
3147 }
else if (!strcasecmp(
name,
"end")) {
3149 }
else if (!strcasecmp(
name,
"duration")) {
3151 }
else if (!strcasecmp(
name,
"billsec")) {
3153 }
else if (!strcasecmp(
name,
"disposition")) {
3155 snprintf(workspace, workspacelen,
"%ld", cdr->
disposition);
3159 }
else if (!strcasecmp(
name,
"amaflags")) {
3161 snprintf(workspace, workspacelen,
"%ld", cdr->
amaflags);
3165 }
else if (!strcasecmp(
name,
"accountcode")) {
3167 }
else if (!strcasecmp(
name,
"peeraccount")) {
3169 }
else if (!strcasecmp(
name,
"uniqueid")) {
3171 }
else if (!strcasecmp(
name,
"linkedid")) {
3173 }
else if (!strcasecmp(
name,
"tenantid")) {
3175 }
else if (!strcasecmp(
name,
"peertenantid")) {
3177 }
else if (!strcasecmp(
name,
"userfield")) {
3179 }
else if (!strcasecmp(
name,
"sequence")) {
3180 snprintf(workspace, workspacelen,
"%d", cdr->
sequence);
3184 workspace[0] =
'\0';
3199 const char *
name = arg;
3215 const char *
name = arg;
3272 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3319 if (!strcasecmp(
name,
"clid")) {
3321 }
else if (!strcasecmp(
name,
"src")) {
3323 }
else if (!strcasecmp(
name,
"dst")) {
3325 }
else if (!strcasecmp(
name,
"dcontext")) {
3327 }
else if (!strcasecmp(
name,
"channel")) {
3329 }
else if (!strcasecmp(
name,
"dstchannel")) {
3335 }
else if (!strcasecmp(
name,
"lastapp")) {
3337 }
else if (!strcasecmp(
name,
"lastdata")) {
3339 }
else if (!strcasecmp(
name,
"start")) {
3341 }
else if (!strcasecmp(
name,
"answer")) {
3343 }
else if (!strcasecmp(
name,
"end")) {
3345 }
else if (!strcasecmp(
name,
"duration")) {
3347 }
else if (!strcasecmp(
name,
"billsec")) {
3349 }
else if (!strcasecmp(
name,
"disposition")) {
3351 }
else if (!strcasecmp(
name,
"amaflags")) {
3353 }
else if (!strcasecmp(
name,
"accountcode")) {
3355 }
else if (!strcasecmp(
name,
"peeraccount")) {
3361 }
else if (!strcasecmp(
name,
"uniqueid")) {
3363 }
else if (!strcasecmp(
name,
"linkedid")) {
3365 }
else if (!strcasecmp(
name,
"tenantid")) {
3367 }
else if (!strcasecmp(
name,
"peertenantid")) {
3373 }
else if (!strcasecmp(
name,
"userfield")) {
3375 }
else if (!strcasecmp(
name,
"sequence")) {
3420 cdr_obj = cdr->
last;
3438 char workspace[256];
3439 int total = 0, x = 0, i;
3452 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3523 return "CONGESTION";
3569 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3597 for (; cdr ; cdr = cdr->
next) {
3602 ast_debug(1,
"Skipping CDR for %s since we weren't answered\n", cdr->
channel);
3618 if (!i->suspended) {
3638 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3665 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3689 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
3691 if (!keep_variables) {
3703 memset(&it_cdr->
start, 0,
sizeof(it_cdr->
start));
3704 memset(&it_cdr->
end, 0,
sizeof(it_cdr->
end));
3731 cdr_obj = cdr->
last;
3742 ast_debug(1,
"Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
3792 for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->
next) {
3837 processeditem = batchitem;
3838 batchitem = batchitem->
next;
3869 ast_debug(1,
"CDR single-threaded batch processing begins now\n");
3873 ast_log(
LOG_WARNING,
"CDR processing thread could not detach, now trying in this thread\n");
3876 ast_debug(1,
"CDR multi-threaded batch processing begins now\n");
3925 int submit_batch = 0;
3946 ast_debug(1,
"CDR detaching from this thread\n");
3949 if (!(newtail =
ast_calloc(1,
sizeof(*newtail)))) {
3971 if (curr >= (mod_cfg->general->batch_settings.size - 1)) {
3984 struct timespec timeout;
3995 timeout.tv_sec = now.tv_sec;
3996 timeout.tv_nsec = now.tv_usec * 1000;
4002 ast_debug(2,
"Processed %d CDR batches from the run queue\n", numevents);
4014 e->
command =
"cdr set debug [on|off]";
4015 e->
usage =
"Enable or disable extra debugging in the CDR Engine. Note\n"
4016 "that this will dump debug information to the VERBOSE setting\n"
4017 "and should only be used when debugging information from the\n"
4018 "CDR engine is needed.\n";
4030 ast_cli(
a->fd,
"Could not set CDR debugging mode\n");
4033 if (!strcasecmp(
a->argv[3],
"on")
4036 ast_cli(
a->fd,
"CDR debugging enabled\n");
4037 }
else if (!strcasecmp(
a->argv[3],
"off")
4040 ast_cli(
a->fd,
"CDR debugging disabled\n");
4051 int wordlen = strlen(
a->word);
4074 char start_time_buffer[64];
4075 char answer_time_buffer[64];
4076 char end_time_buffer[64];
4078#define TITLE_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4079#define FORMAT_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4082 ast_cli(
a->fd,
"Channels with Call Detail Record (CDR) Information\n");
4083 ast_cli(
a->fd,
"--------------------------------------------------\n");
4084 ast_cli(
a->fd,
TITLE_STRING,
"Channel",
"Dst. Channel",
"LastApp",
"Start",
"Answer",
"End",
"Billsec",
"Duration");
4089 struct timeval start_time = { 0, };
4090 struct timeval answer_time = { 0, };
4091 struct timeval end_time = { 0, };
4098 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
4103 start_time = it_cdr->
start;
4106 answer_time = it_cdr->
answer;
4117 cdr_get_tv(start_time,
"%T", start_time_buffer,
sizeof(start_time_buffer));
4118 cdr_get_tv(answer_time,
"%T", answer_time_buffer,
sizeof(answer_time_buffer));
4119 cdr_get_tv(end_time,
"%T", end_time_buffer,
sizeof(end_time_buffer));
4138 char start_time_buffer[64];
4139 char answer_time_buffer[64];
4140 char end_time_buffer[64];
4141 const char *channel_name =
a->argv[3];
4144#define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4145#define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4149 ast_cli(
a->fd,
"Unknown channel: %s\n", channel_name);
4154 ast_cli(
a->fd,
"Call Detail Record (CDR) Information for %s\n", channel_name);
4155 ast_cli(
a->fd,
"--------------------------------------------------\n");
4156 ast_cli(
a->fd,
TITLE_STRING,
"AccountCode",
"CallerID",
"Dst. Channel",
"LastApp",
"Data",
"Start",
"Answer",
"End",
"Billsec",
"Duration");
4159 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->
next) {
4171 cdr_get_tv(it_cdr->
start,
"%T", start_time_buffer,
sizeof(start_time_buffer));
4172 cdr_get_tv(it_cdr->
answer,
"%T", answer_time_buffer,
sizeof(answer_time_buffer));
4173 cdr_get_tv(
end,
"%T", end_time_buffer,
sizeof(end_time_buffer));
4198 e->
command =
"cdr show active";
4200 "Usage: cdr show active [channel]\n"
4201 " Displays a summary of all Call Detail Records when [channel]\n"
4202 " is omitted; displays all of the Call Detail Records\n"
4203 " currently in flight for a given [channel] when [channel] is\n"
4205 " Note that this will not display Call Detail Records that\n"
4206 " have already been dispatched to a backend storage, nor for\n"
4207 " channels that are no longer active.\n";
4215 }
else if (
a->argc < 4) {
4229 long nextbatchtime = 0;
4233 e->
command =
"cdr show status";
4235 "Usage: cdr show status\n"
4236 " Displays the Call Detail Record engine system status.\n";
4252 ast_cli(
a->fd,
"Call Detail Record (CDR) settings\n");
4253 ast_cli(
a->fd,
"----------------------------------\n");
4263 ast_cli(
a->fd,
"* Batch Mode Settings\n");
4264 ast_cli(
a->fd,
" -------------------\n");
4271 ast_cli(
a->fd,
" Current batch size: %d record%s\n", cnt,
ESS(cnt));
4274 ast_cli(
a->fd,
" Next batch processing time: %ld second%s\n\n", nextbatchtime,
ESS(nextbatchtime));
4276 ast_cli(
a->fd,
"* Registered Backends\n");
4277 ast_cli(
a->fd,
" -------------------\n");