Skip to content
Snippets Groups Projects
cdr.c 33.4 KiB
Newer Older
Mark Spencer's avatar
Mark Spencer committed
/*
 * Asterisk -- An open source telephony toolkit.
Mark Spencer's avatar
Mark Spencer committed
 *
 * Copyright (C) 1999 - 2005, Digium, Inc.
Mark Spencer's avatar
Mark Spencer committed
 *
 * Mark Spencer <markster@digium.com>
Mark Spencer's avatar
Mark Spencer committed
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
Mark Spencer's avatar
Mark Spencer committed
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

Mark Spencer's avatar
Mark Spencer committed
 *
 * \brief Call Detail Record API 
Mark Spencer's avatar
Mark Spencer committed
 * Includes code and algorithms from the Zapata library.
 *
 */

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "asterisk.h"

Kevin P. Fleming's avatar
Kevin P. Fleming committed
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#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's avatar
Kevin P. Fleming committed
#include "asterisk/linkedlists.h"
#include "asterisk/sched.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/module.h"
Mark Spencer's avatar
Mark Spencer committed

int ast_default_amaflags = AST_CDR_DOCUMENTATION;
char ast_default_accountcode[AST_MAX_ACCOUNT_CODE] = "";
Kevin P. Fleming's avatar
Kevin P. Fleming committed
struct ast_cdr_beitem {
Mark Spencer's avatar
Mark Spencer committed
	char name[20];
	char desc[80];
	ast_cdrbe be;
Kevin P. Fleming's avatar
Kevin P. Fleming committed
	AST_LIST_ENTRY(ast_cdr_beitem) list;
};
Kevin P. Fleming's avatar
Kevin P. Fleming committed
static AST_LIST_HEAD_STATIC(be_list, ast_cdr_beitem);
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);
Mark Spencer's avatar
Mark Spencer committed
/*
 * 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;
Kevin P. Fleming's avatar
Kevin P. Fleming committed

Mark Spencer's avatar
Mark Spencer committed
	if (!name)
		return -1;
	if (!be) {
		ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
		return -1;
	}
Kevin P. Fleming's avatar
Kevin P. Fleming committed

	AST_LIST_LOCK(&be_list);
	AST_LIST_TRAVERSE(&be_list, i, list) {
Mark Spencer's avatar
Mark Spencer committed
		if (!strcasecmp(name, i->name))
			break;
	}
Kevin P. Fleming's avatar
Kevin P. Fleming committed
	AST_LIST_UNLOCK(&be_list);

Mark Spencer's avatar
Mark Spencer committed
	if (i) {
		ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
		return -1;
	}
Kevin P. Fleming's avatar
Kevin P. Fleming committed

	i = malloc(sizeof(*i));
Mark Spencer's avatar
Mark Spencer committed
	if (!i) 	
		return -1;
Kevin P. Fleming's avatar
Kevin P. Fleming committed

	memset(i, 0, sizeof(*i));
Mark Spencer's avatar
Mark Spencer committed
	i->be = be;
Kevin P. Fleming's avatar
Kevin P. Fleming committed
	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);

Mark Spencer's avatar
Mark Spencer committed
	return 0;
}

void ast_cdr_unregister(char *name)
{
Kevin P. Fleming's avatar
Kevin P. Fleming committed
	struct ast_cdr_beitem *i = NULL;

	AST_LIST_LOCK(&be_list);
	AST_LIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
Mark Spencer's avatar
Mark Spencer committed
		if (!strcasecmp(name, i->name)) {
Kevin P. Fleming's avatar
Kevin P. Fleming committed
			AST_LIST_REMOVE_CURRENT(&be_list, list);
			if (option_verbose > 1)
				ast_verbose(VERBOSE_PREFIX_2 "Unregistered '%s' CDR backend\n", name);
			free(i);
Mark Spencer's avatar
Mark Spencer committed
			break;
		}
	}
Kevin P. Fleming's avatar
Kevin P. Fleming committed
	AST_LIST_TRAVERSE_SAFE_END;
	AST_LIST_UNLOCK(&be_list);
struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr) 
Mark Spencer's avatar
Mark Spencer committed

	if (!(newcdr = ast_cdr_alloc())) {
		ast_log(LOG_ERROR, "Memory Error!\n");
	memcpy(newcdr, cdr, sizeof(*newcdr));
	/* The varshead is unusable, volatile even, after the memcpy so we take care of that here */
	memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
	ast_cdr_copy_vars(newcdr, cdr);
	newcdr->next = NULL;
Mark Spencer's avatar
Mark Spencer committed
	return newcdr;
}

static const char *ast_cdr_getvar_internal(struct ast_cdr *cdr, const char *name, int recur) 
{
	struct ast_var_t *variables;
	struct varshead *headp;

Kevin P. Fleming's avatar
Kevin P. Fleming committed
		return NULL;

	while (cdr) {
		headp = &cdr->varshead;
Kevin P. Fleming's avatar
Kevin P. Fleming committed
		AST_LIST_TRAVERSE(headp, variables, entries) {
			if (!strcasecmp(name, ast_var_name(variables)))
				return ast_var_value(variables);
Kevin P. Fleming's avatar
Kevin P. Fleming committed
		if (!recur)
			break;
		cdr = cdr->next;
	}
Kevin P. Fleming's avatar
Kevin P. Fleming committed

	return NULL;
}

void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur) 
Loading
Loading full blame...