Newer
Older
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Call Detail Record API
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Mark Spencer <markster@digium.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License.
*
* Includes code and algorithms from the Zapata library.
*
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include "asterisk.h"
ASTERISK_FILE_VERSION("$Revision$")
Kevin P. Fleming
committed
#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"
Kevin P. Fleming
committed
#include "asterisk/utils.h"
#include "asterisk/sched.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/module.h"
int ast_default_amaflags = AST_CDR_DOCUMENTATION;
char ast_default_accountcode[AST_MAX_ACCOUNT_CODE] = "";
struct ast_cdr_batch_item {
struct ast_cdr *cdr;
struct ast_cdr_batch_item *next;
};
static struct ast_cdr_batch {
int size;
struct ast_cdr_batch_item *head;
struct ast_cdr_batch_item *tail;
} *batch = NULL;
static struct sched_context *sched;
static int cdr_sched = -1;
static pthread_t cdr_thread = AST_PTHREADT_NULL;
#define BATCH_SIZE_DEFAULT 100
#define BATCH_TIME_DEFAULT 300
#define BATCH_SCHEDULER_ONLY_DEFAULT 0
#define BATCH_SAFE_SHUTDOWN_DEFAULT 1
static int enabled;
static int batchmode;
static int batchsize;
static int batchtime;
static int batchscheduleronly;
static int batchsafeshutdown;
AST_MUTEX_DEFINE_STATIC(cdr_batch_lock);
/* these are used to wake up the CDR thread when there's work to do */
AST_MUTEX_DEFINE_STATIC(cdr_pending_lock);
pthread_cond_t cdr_pending_cond;
/*
* 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.
*/
int ast_cdr_register(char *name, char *desc, ast_cdrbe be)
{
struct ast_cdr_beitem *i;
if (!name)
return -1;
if (!be) {
ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
return -1;
}
AST_LIST_LOCK(&be_list);
AST_LIST_TRAVERSE(&be_list, i, list) {
if (i) {
ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
return -1;
}
ast_copy_string(i->name, name, sizeof(i->name));
ast_copy_string(i->desc, desc, sizeof(i->desc));
AST_LIST_LOCK(&be_list);
AST_LIST_INSERT_HEAD(&be_list, i, list);
AST_LIST_UNLOCK(&be_list);
return 0;
}
void ast_cdr_unregister(char *name)
{
struct ast_cdr_beitem *i = NULL;
AST_LIST_LOCK(&be_list);
AST_LIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
AST_LIST_REMOVE_CURRENT(&be_list, list);
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Unregistered '%s' CDR backend\n", name);
free(i);
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&be_list);
static const char *ast_cdr_getvar_internal(struct ast_cdr *cdr, const char *name, int recur)
{
struct ast_var_t *variables;
struct varshead *headp;
if (!name || ast_strlen_zero(name))
return NULL;
while (cdr) {
AST_LIST_TRAVERSE(headp, variables, entries) {
if (!strcasecmp(name, ast_var_name(variables)))
return ast_var_value(variables);
return NULL;
}
void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur)
{
struct tm tm;
time_t t;
const char *fmt = "%Y-%m-%d %T";
*ret = NULL;
/* special vars (the ones from the struct ast_cdr when requested by name)
I'd almost say we should convert all the stringed vals to vars */
if (!strcasecmp(name, "clid"))
ast_copy_string(workspace, cdr->clid, workspacelen);
else if (!strcasecmp(name, "src"))
ast_copy_string(workspace, cdr->src, workspacelen);
else if (!strcasecmp(name, "dst"))
ast_copy_string(workspace, cdr->dst, workspacelen);
else if (!strcasecmp(name, "dcontext"))
ast_copy_string(workspace, cdr->dcontext, workspacelen);
else if (!strcasecmp(name, "channel"))
ast_copy_string(workspace, cdr->channel, workspacelen);
else if (!strcasecmp(name, "dstchannel"))
ast_copy_string(workspace, cdr->dstchannel, workspacelen);
else if (!strcasecmp(name, "lastapp"))
ast_copy_string(workspace, cdr->lastapp, workspacelen);
else if (!strcasecmp(name, "lastdata"))
ast_copy_string(workspace, cdr->lastdata, workspacelen);
else if (!strcasecmp(name, "start")) {
Loading
Loading full blame...