diff options
Diffstat (limited to 'cdr')
-rw-r--r-- | cdr/Makefile | 32 | ||||
-rw-r--r-- | cdr/cdr_csv.c | 365 | ||||
-rw-r--r-- | cdr/cdr_custom.c | 174 | ||||
-rw-r--r-- | cdr/cdr_manager.c | 170 | ||||
-rw-r--r-- | cdr/cdr_odbc.c | 481 | ||||
-rw-r--r-- | cdr/cdr_pgsql.c | 336 | ||||
-rw-r--r-- | cdr/cdr_radius.c | 273 | ||||
-rw-r--r-- | cdr/cdr_sqlite.c | 217 | ||||
-rw-r--r-- | cdr/cdr_tds.c | 630 |
9 files changed, 0 insertions, 2678 deletions
diff --git a/cdr/Makefile b/cdr/Makefile deleted file mode 100644 index b7e854468..000000000 --- a/cdr/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# Asterisk -- A telephony toolkit for Linux. -# -# Makefile for CDR backends -# -# Copyright (C) 1999-2006, Digium, Inc. -# -# This program is free software, distributed under the terms of -# the GNU General Public License -# - --include ../menuselect.makeopts ../menuselect.makedeps - -MENUSELECT_CATEGORY=CDR -MENUSELECT_DESCRIPTION=Call Detail Recording - -ALL_C_MODS:=$(patsubst %.c,%,$(wildcard cdr_*.c)) -ALL_CC_MODS:=$(patsubst %.cc,%,$(wildcard cdr_*.cc)) - -C_MODS:=$(filter-out $(MENUSELECT_CDR),$(ALL_C_MODS)) -CC_MODS:=$(filter-out $(MENUSELECT_CDR),$(ALL_CC_MODS)) - -LOADABLE_MODS:=$(C_MODS) $(CC_MODS) - -ifneq ($(findstring cdr,$(MENUSELECT_EMBED)),) - EMBEDDED_MODS:=$(LOADABLE_MODS) - LOADABLE_MODS:= -endif - -all: _all - -include $(ASTTOPDIR)/Makefile.moddir_rules diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c deleted file mode 100644 index cdaef6853..000000000 --- a/cdr/cdr_csv.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * Includes code and algorithms from the Zapata library. - * - * 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. - * - * 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. - */ - -/*! \file - * - * \brief Comma Separated Value CDR records. - * - * \author Mark Spencer <markster@digium.com> - * - * \arg See also \ref AstCDR - * \ingroup cdr_drivers - */ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <sys/types.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> - -#include <stdlib.h> -#include <unistd.h> -#include <time.h> - -#include "asterisk/config.h" -#include "asterisk/channel.h" -#include "asterisk/cdr.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" -#include "asterisk/utils.h" -#include "asterisk/lock.h" - -#define CSV_LOG_DIR "/cdr-csv" -#define CSV_MASTER "/Master.csv" - -#define DATE_FORMAT "%Y-%m-%d %T" - -static int usegmtime = 0; -static int loguniqueid = 0; -static int loguserfield = 0; -static int loaded = 0; -static char *config = "cdr.conf"; - -/* #define CSV_LOGUNIQUEID 1 */ -/* #define CSV_LOGUSERFIELD 1 */ - -/*---------------------------------------------------- - The values are as follows: - - - "accountcode", accountcode is the account name of detail records, Master.csv contains all records * - Detail records are configured on a channel basis, IAX and SIP are determined by user * - DAHDI is determined by channel in chan_dahdi.conf - "source", - "destination", - "destination context", - "callerid", - "channel", - "destination channel", (if applicable) - "last application", Last application run on the channel - "last app argument", argument to the last channel - "start time", - "answer time", - "end time", - duration, Duration is the whole length that the entire call lasted. ie. call rx'd to hangup - "end time" minus "start time" - billable seconds, the duration that a call was up after other end answered which will be <= to duration - "end time" minus "answer time" - "disposition", ANSWERED, NO ANSWER, BUSY - "amaflags", DOCUMENTATION, BILL, IGNORE etc, specified on a per channel basis like accountcode. - "uniqueid", unique call identifier - "userfield" user field set via SetCDRUserField -----------------------------------------------------------*/ - -static char *name = "csv"; - -AST_MUTEX_DEFINE_STATIC(mf_lock); -AST_MUTEX_DEFINE_STATIC(acf_lock); - -static int load_config(void) -{ - struct ast_config *cfg; - struct ast_variable *var; - const char *tmp; - - usegmtime = 0; - loguniqueid = 0; - loguserfield = 0; - - cfg = ast_config_load(config); - - if (!cfg) { - ast_log(LOG_WARNING, "unable to load config: %s\n", config); - return 0; - } - - var = ast_variable_browse(cfg, "csv"); - if (!var) { - ast_config_destroy(cfg); - return 0; - } - - tmp = ast_variable_retrieve(cfg, "csv", "usegmtime"); - if (tmp) { - usegmtime = ast_true(tmp); - if (usegmtime) { - ast_log(LOG_DEBUG, "logging time in GMT\n"); - } - } - - tmp = ast_variable_retrieve(cfg, "csv", "loguniqueid"); - if (tmp) { - loguniqueid = ast_true(tmp); - if (loguniqueid) { - ast_log(LOG_DEBUG, "logging CDR field UNIQUEID\n"); - } - } - - tmp = ast_variable_retrieve(cfg, "csv", "loguserfield"); - if (tmp) { - loguserfield = ast_true(tmp); - if (loguserfield) { - ast_log(LOG_DEBUG, "logging CDR user-defined field\n"); - } - } - - ast_config_destroy(cfg); - return 1; -} - -static int append_string(char *buf, char *s, size_t bufsize) -{ - int pos = strlen(buf); - int spos = 0; - int error = 0; - if (pos >= bufsize - 4) - return -1; - buf[pos++] = '\"'; - error = -1; - while(pos < bufsize - 3) { - if (!s[spos]) { - error = 0; - break; - } - if (s[spos] == '\"') - buf[pos++] = '\"'; - buf[pos++] = s[spos]; - spos++; - } - buf[pos++] = '\"'; - buf[pos++] = ','; - buf[pos++] = '\0'; - return error; -} - -static int append_int(char *buf, int s, size_t bufsize) -{ - char tmp[32]; - int pos = strlen(buf); - snprintf(tmp, sizeof(tmp), "%d", s); - if (pos + strlen(tmp) > bufsize - 3) - return -1; - strncat(buf, tmp, bufsize - strlen(buf) - 1); - pos = strlen(buf); - buf[pos++] = ','; - buf[pos++] = '\0'; - return 0; -} - -static int append_date(char *buf, struct timeval tv, size_t bufsize) -{ - char tmp[80] = ""; - struct tm tm; - time_t t; - t = tv.tv_sec; - if (strlen(buf) > bufsize - 3) - return -1; - if (ast_tvzero(tv)) { - strncat(buf, ",", bufsize - strlen(buf) - 1); - return 0; - } - if (usegmtime) { - gmtime_r(&t,&tm); - } else { - ast_localtime(&t, &tm, NULL); - } - strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm); - return append_string(buf, tmp, bufsize); -} - -static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr) -{ - - buf[0] = '\0'; - /* Account code */ - append_string(buf, cdr->accountcode, bufsize); - /* Source */ - append_string(buf, cdr->src, bufsize); - /* Destination */ - append_string(buf, cdr->dst, bufsize); - /* Destination context */ - append_string(buf, cdr->dcontext, bufsize); - /* Caller*ID */ - append_string(buf, cdr->clid, bufsize); - /* Channel */ - append_string(buf, cdr->channel, bufsize); - /* Destination Channel */ - append_string(buf, cdr->dstchannel, bufsize); - /* Last Application */ - append_string(buf, cdr->lastapp, bufsize); - /* Last Data */ - append_string(buf, cdr->lastdata, bufsize); - /* Start Time */ - append_date(buf, cdr->start, bufsize); - /* Answer Time */ - append_date(buf, cdr->answer, bufsize); - /* End Time */ - append_date(buf, cdr->end, bufsize); - /* Duration */ - append_int(buf, cdr->duration, bufsize); - /* Billable seconds */ - append_int(buf, cdr->billsec, bufsize); - /* Disposition */ - append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize); - /* AMA Flags */ - append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize); - /* Unique ID */ - if (loguniqueid) - append_string(buf, cdr->uniqueid, bufsize); - /* append the user field */ - if(loguserfield) - append_string(buf, cdr->userfield,bufsize); - /* If we hit the end of our buffer, log an error */ - if (strlen(buf) < bufsize - 5) { - /* Trim off trailing comma */ - buf[strlen(buf) - 1] = '\0'; - strncat(buf, "\n", bufsize - strlen(buf) - 1); - return 0; - } - return -1; -} - -static int writefile(char *s, char *acc) -{ - char tmp[PATH_MAX]; - FILE *f; - if (strchr(acc, '/') || (acc[0] == '.')) { - ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc); - return -1; - } - snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", (char *)ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc); - - ast_mutex_lock(&acf_lock); - f = fopen(tmp, "a"); - if (!f) { - ast_mutex_unlock(&acf_lock); - ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno)); - return -1; - } - fputs(s, f); - fflush(f); - fclose(f); - ast_mutex_unlock(&acf_lock); - - return 0; -} - - -static int csv_log(struct ast_cdr *cdr) -{ - FILE *mf = NULL; - /* Make sure we have a big enough buf */ - char buf[1024]; - char csvmaster[PATH_MAX]; - snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER); -#if 0 - printf("[CDR] %s ('%s' -> '%s') Dur: %ds Bill: %ds Disp: %s Flags: %s Account: [%s]\n", cdr->channel, cdr->src, cdr->dst, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->accountcode); -#endif - if (build_csv_record(buf, sizeof(buf), cdr)) { - ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf)); - } else { - /* because of the absolutely unconditional need for the - highest reliability possible in writing billing records, - we open write and close the log file each time */ - ast_mutex_lock(&mf_lock); - mf = fopen(csvmaster, "a"); - if (mf) { - fputs(buf, mf); - fflush(mf); /* be particularly anal here */ - fclose(mf); - mf = NULL; - ast_mutex_unlock(&mf_lock); - } else { - ast_mutex_unlock(&mf_lock); - ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno)); - } - - if (!ast_strlen_zero(cdr->accountcode)) { - if (writefile(buf, cdr->accountcode)) - ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno)); - } - } - return 0; -} - -static int unload_module(void) -{ - ast_cdr_unregister(name); - loaded = 0; - return 0; -} - -static int load_module(void) -{ - int res; - - if(!load_config()) - return AST_MODULE_LOAD_DECLINE; - - res = ast_cdr_register(name, ast_module_info->description, csv_log); - if (res) { - ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n"); - } else { - loaded = 1; - } - return res; -} - -static int reload(void) -{ - if (load_config()) { - loaded = 1; - } else { - loaded = 0; - ast_log(LOG_WARNING, "No [csv] section in cdr.conf. Unregistering backend.\n"); - ast_cdr_unregister(name); - } - - return 0; -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Comma Separated Values CDR Backend", - .load = load_module, - .unload = unload_module, - .reload = reload, - ); diff --git a/cdr/cdr_custom.c b/cdr/cdr_custom.c deleted file mode 100644 index c390b0499..000000000 --- a/cdr/cdr_custom.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * Includes code and algorithms from the Zapata library. - * - * 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. - * - * 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. - */ - -/*! \file - * - * \brief Custom Comma Separated Value CDR records. - * - * \author Mark Spencer <markster@digium.com> - * - * \arg See also \ref AstCDR - * - * Logs in LOG_DIR/cdr_custom - * \ingroup cdr_drivers - */ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <sys/types.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> - -#include <stdlib.h> -#include <unistd.h> -#include <time.h> - -#include "asterisk/channel.h" -#include "asterisk/cdr.h" -#include "asterisk/module.h" -#include "asterisk/config.h" -#include "asterisk/pbx.h" -#include "asterisk/logger.h" -#include "asterisk/utils.h" -#include "asterisk/lock.h" - -#define CUSTOM_LOG_DIR "/cdr_custom" - -#define DATE_FORMAT "%Y-%m-%d %T" - -AST_MUTEX_DEFINE_STATIC(lock); -AST_MUTEX_DEFINE_STATIC(mf_lock); - -static char *name = "cdr-custom"; - -static char master[PATH_MAX]; -static char format[1024]=""; - -static int load_config(int reload) -{ - struct ast_config *cfg; - struct ast_variable *var; - int res = -1; - - strcpy(format, ""); - strcpy(master, ""); - ast_mutex_lock(&lock); - if((cfg = ast_config_load("cdr_custom.conf"))) { - var = ast_variable_browse(cfg, "mappings"); - while(var) { - if (!ast_strlen_zero(var->name) && !ast_strlen_zero(var->value)) { - if (strlen(var->value) > (sizeof(format) - 1)) - ast_log(LOG_WARNING, "Format string too long, will be truncated, at line %d\n", var->lineno); - ast_copy_string(format, var->value, sizeof(format) - 1); - strcat(format,"\n"); - snprintf(master, sizeof(master),"%s/%s/%s", ast_config_AST_LOG_DIR, name, var->name); - if (var->next) { - ast_log(LOG_NOTICE, "Sorry, only one mapping is supported at this time, mapping '%s' will be ignored at line %d.\n", var->next->name, var->next->lineno); - break; - } - } else - ast_log(LOG_NOTICE, "Mapping must have both filename and format at line %d\n", var->lineno); - var = var->next; - } - ast_config_destroy(cfg); - res = 0; - } else { - if (reload) - ast_log(LOG_WARNING, "Failed to reload configuration file.\n"); - else - ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n"); - } - ast_mutex_unlock(&lock); - - return res; -} - - - -static int custom_log(struct ast_cdr *cdr) -{ - FILE *mf = NULL; - - /* Make sure we have a big enough buf */ - char buf[2048]; - struct ast_channel dummy; - - /* Abort if no master file is specified */ - if (ast_strlen_zero(master)) - return 0; - - memset(buf, 0 , sizeof(buf)); - /* Quite possibly the first use of a static struct ast_channel, we need it so the var funcs will work */ - memset(&dummy, 0, sizeof(dummy)); - dummy.cdr = cdr; - pbx_substitute_variables_helper(&dummy, format, buf, sizeof(buf) - 1); - - /* because of the absolutely unconditional need for the - highest reliability possible in writing billing records, - we open write and close the log file each time */ - ast_mutex_lock(&mf_lock); - mf = fopen(master, "a"); - if (mf) { - fputs(buf, mf); - fflush(mf); /* be particularly anal here */ - fclose(mf); - mf = NULL; - ast_mutex_unlock(&mf_lock); - } else { - ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", master, strerror(errno)); - ast_mutex_unlock(&mf_lock); - } - - return 0; -} - -static int unload_module(void) -{ - ast_cdr_unregister(name); - return 0; -} - -static int load_module(void) -{ - int res = 0; - - if (!load_config(0)) { - res = ast_cdr_register(name, ast_module_info->description, custom_log); - if (res) - ast_log(LOG_ERROR, "Unable to register custom CDR handling\n"); - return res; - } else - return AST_MODULE_LOAD_DECLINE; -} - -static int reload(void) -{ - return load_config(1); -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Customizable Comma Separated Values CDR Backend", - .load = load_module, - .unload = unload_module, - .reload = reload, - ); - diff --git a/cdr/cdr_manager.c b/cdr/cdr_manager.c deleted file mode 100644 index 352d7d400..000000000 --- a/cdr/cdr_manager.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2004 - 2005 - * - * 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. - * - * 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. - */ - -/*! \file - * - * \brief Asterisk Call Manager CDR records. - * - * See also - * \arg \ref AstCDR - * \arg \ref AstAMI - * \arg \ref Config_ami - * \ingroup cdr_drivers - */ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <sys/types.h> -#include <strings.h> -#include <unistd.h> -#include <time.h> - -#include "asterisk/channel.h" -#include "asterisk/cdr.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" -#include "asterisk/utils.h" -#include "asterisk/manager.h" -#include "asterisk/config.h" - -#define DATE_FORMAT "%Y-%m-%d %T" -#define CONF_FILE "cdr_manager.conf" - -static char *name = "cdr_manager"; - -static int enablecdr = 0; - -static int loadconfigurationfile(void) -{ - char *cat; - struct ast_config *cfg; - struct ast_variable *v; - - cfg = ast_config_load(CONF_FILE); - if (!cfg) { - /* Standard configuration */ - enablecdr = 0; - return 0; - } - - cat = ast_category_browse(cfg, NULL); - while (cat) { - if (!strcasecmp(cat, "general")) { - v = ast_variable_browse(cfg, cat); - while (v) { - if (!strcasecmp(v->name, "enabled")) { - enablecdr = ast_true(v->value); - } - - v = v->next; - } - } - - /* Next category */ - cat = ast_category_browse(cfg, cat); - } - - ast_config_destroy(cfg); - return 1; -} - -static int manager_log(struct ast_cdr *cdr) -{ - time_t t; - struct tm timeresult; - char strStartTime[80] = ""; - char strAnswerTime[80] = ""; - char strEndTime[80] = ""; - - if (!enablecdr) - return 0; - - t = cdr->start.tv_sec; - ast_localtime(&t, &timeresult, NULL); - strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult); - - if (cdr->answer.tv_sec) { - t = cdr->answer.tv_sec; - ast_localtime(&t, &timeresult, NULL); - strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult); - } - - t = cdr->end.tv_sec; - ast_localtime(&t, &timeresult, NULL); - strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult); - - manager_event(EVENT_FLAG_CALL, "Cdr", - "AccountCode: %s\r\n" - "Source: %s\r\n" - "Destination: %s\r\n" - "DestinationContext: %s\r\n" - "CallerID: %s\r\n" - "Channel: %s\r\n" - "DestinationChannel: %s\r\n" - "LastApplication: %s\r\n" - "LastData: %s\r\n" - "StartTime: %s\r\n" - "AnswerTime: %s\r\n" - "EndTime: %s\r\n" - "Duration: %ld\r\n" - "BillableSeconds: %ld\r\n" - "Disposition: %s\r\n" - "AMAFlags: %s\r\n" - "UniqueID: %s\r\n" - "UserField: %s\r\n", - cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel, - cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime, - cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), - ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield); - - return 0; -} - -static int unload_module(void) -{ - ast_cdr_unregister(name); - return 0; -} - -static int load_module(void) -{ - int res; - - /* Configuration file */ - if (!loadconfigurationfile()) - return AST_MODULE_LOAD_DECLINE; - - res = ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log); - if (res) { - ast_log(LOG_ERROR, "Unable to register Asterisk Call Manager CDR handling\n"); - } - - return res; -} - -static int reload(void) -{ - loadconfigurationfile(); - return 0; -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Manager Interface CDR Backend", - .load = load_module, - .unload = unload_module, - .reload = reload, - ); diff --git a/cdr/cdr_odbc.c b/cdr/cdr_odbc.c deleted file mode 100644 index da8327375..000000000 --- a/cdr/cdr_odbc.c +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2003-2005, Digium, Inc. - * - * Brian K. West <brian@bkw.org> - * - * 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. - * - * 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. - */ - -/*! \file - * - * \brief ODBC CDR Backend - * - * \author Brian K. West <brian@bkw.org> - * - * See also: - * \arg http://www.unixodbc.org - * \arg \ref Config_cdr - * \ingroup cdr_drivers - */ - -/*** MODULEINFO - <depend>unixodbc</depend> - <depend>ltdl</depend> - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <sys/types.h> -#include <stdio.h> -#include <string.h> - -#include <stdlib.h> -#include <unistd.h> -#include <time.h> - -#ifndef __CYGWIN__ -#include <sql.h> -#include <sqlext.h> -#include <sqltypes.h> -#else -#include <windows.h> -#include <w32api/sql.h> -#include <w32api/sqlext.h> -#include <w32api/sqltypes.h> -#endif - -#include "asterisk/config.h" -#include "asterisk/options.h" -#include "asterisk/channel.h" -#include "asterisk/cdr.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" - -#define DATE_FORMAT "%Y-%m-%d %T" - -static char *name = "ODBC"; -static char *config = "cdr_odbc.conf"; -static char *dsn = NULL, *username = NULL, *password = NULL, *table = NULL; -static int loguniqueid = 0; -static int usegmtime = 0; -static int dispositionstring = 0; -static int connected = 0; - -AST_MUTEX_DEFINE_STATIC(odbc_lock); - -static int odbc_do_query(void); -static int odbc_init(void); - -static SQLHENV ODBC_env = SQL_NULL_HANDLE; /* global ODBC Environment */ -static SQLHDBC ODBC_con; /* global ODBC Connection Handle */ -static SQLHSTMT ODBC_stmt; /* global ODBC Statement Handle */ - -static void odbc_disconnect(void) -{ - ODBC_stmt = SQL_NULL_HANDLE; - SQLDisconnect(ODBC_con); - SQLFreeHandle(SQL_HANDLE_DBC, ODBC_con); - ODBC_con = SQL_NULL_HANDLE; - SQLFreeHandle(SQL_HANDLE_ENV, ODBC_env); - ODBC_env = SQL_NULL_HANDLE; - connected = 0; -} - -static void build_query(struct ast_cdr *cdr, char *timestr, int timesize) -{ - int ODBC_res; - char sqlcmd[2048] = ""; - int res = 0; - struct tm tm; - - if (usegmtime) - gmtime_r(&cdr->start.tv_sec,&tm); - else - ast_localtime(&cdr->start.tv_sec, &tm, NULL); - - strftime(timestr, timesize, DATE_FORMAT, &tm); - memset(sqlcmd,0,2048); - if (loguniqueid) { - snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s " - "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp," - "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) " - "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table); - } else { - snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s " - "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata," - "duration,billsec,disposition,amaflags,accountcode) " - "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table); - } - if (!connected) { - res = odbc_init(); - if (res < 0) { - odbc_disconnect(); - return; - } - } - - ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, ODBC_con, &ODBC_stmt); - - if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res); - SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); - ODBC_stmt = SQL_NULL_HANDLE; - odbc_disconnect(); - return; - } - - /* We really should only have to do this once. But for some - strange reason if I don't it blows holes in memory like - like a shotgun. So we just do this so its safe. */ - - ODBC_res = SQLPrepare(ODBC_stmt, (unsigned char *)sqlcmd, SQL_NTS); - - if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error in PREPARE %d\n", ODBC_res); - SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); - ODBC_stmt = SQL_NULL_HANDLE; - odbc_disconnect(); - return; - } - - SQLBindParameter(ODBC_stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, timesize, 0, timestr, 0, NULL); - SQLBindParameter(ODBC_stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL); - SQLBindParameter(ODBC_stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL); - SQLBindParameter(ODBC_stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL); - SQLBindParameter(ODBC_stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL); - SQLBindParameter(ODBC_stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL); - SQLBindParameter(ODBC_stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL); - SQLBindParameter(ODBC_stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL); - SQLBindParameter(ODBC_stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL); - SQLBindParameter(ODBC_stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL); - SQLBindParameter(ODBC_stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL); - if (dispositionstring) - SQLBindParameter(ODBC_stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ast_cdr_disp2str(cdr->disposition)) + 1, 0, ast_cdr_disp2str(cdr->disposition), 0, NULL); - else - SQLBindParameter(ODBC_stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL); - SQLBindParameter(ODBC_stmt, 13, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL); - SQLBindParameter(ODBC_stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL); - - if (loguniqueid) { - SQLBindParameter(ODBC_stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL); - SQLBindParameter(ODBC_stmt, 16, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL); - } -} - -static int odbc_log(struct ast_cdr *cdr) -{ - int res = 0; - char timestr[150]; - - ast_mutex_lock(&odbc_lock); - build_query(cdr, timestr, sizeof(timestr)); - - if (connected) { - res = odbc_do_query(); - if (res < 0) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Reconnecting to dsn %s\n", dsn); - odbc_disconnect(); - res = odbc_init(); - if (res < 0) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: %s has gone away!\n", dsn); - odbc_disconnect(); - } else { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Trying Query again!\n"); - SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); - ODBC_stmt = SQL_NULL_HANDLE; - build_query(cdr, timestr, sizeof(timestr)); /* what a waste. If we have to reconnect, we have to build a new query */ - res = odbc_do_query(); - if (res < 0) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n"); - } - } - } - } else { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n"); - } - SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); - ODBC_stmt = SQL_NULL_HANDLE; - ast_mutex_unlock(&odbc_lock); - return 0; -} - -static int odbc_unload_module(void) -{ - ast_mutex_lock(&odbc_lock); - if (connected) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Disconnecting from %s\n", dsn); - SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); - ODBC_stmt = SQL_NULL_HANDLE; - odbc_disconnect(); - } - if (dsn) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: free dsn\n"); - free(dsn); - } - if (username) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: free username\n"); - free(username); - } - if (password) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: free password\n"); - free(password); - } - if (table) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: free table\n"); - free(table); - } - - ast_cdr_unregister(name); - ast_mutex_unlock(&odbc_lock); - return 0; -} - -static int odbc_load_module(void) -{ - int res = 0; - struct ast_config *cfg; - struct ast_variable *var; - const char *tmp; - - ast_mutex_lock(&odbc_lock); - - cfg = ast_config_load(config); - if (!cfg) { - ast_log(LOG_WARNING, "cdr_odbc: Unable to load config for ODBC CDR's: %s\n", config); - res = AST_MODULE_LOAD_DECLINE; - goto out; - } - - var = ast_variable_browse(cfg, "global"); - if (!var) { - /* nothing configured */ - goto out; - } - - tmp = ast_variable_retrieve(cfg,"global","dsn"); - if (tmp == NULL) { - ast_log(LOG_WARNING,"cdr_odbc: dsn not specified. Assuming asteriskdb\n"); - tmp = "asteriskdb"; - } - dsn = strdup(tmp); - if (dsn == NULL) { - ast_log(LOG_ERROR,"cdr_odbc: Out of memory error.\n"); - res = -1; - goto out; - } - - tmp = ast_variable_retrieve(cfg,"global","dispositionstring"); - if (tmp) { - dispositionstring = ast_true(tmp); - } else { - dispositionstring = 0; - } - - tmp = ast_variable_retrieve(cfg,"global","username"); - if (tmp) { - username = strdup(tmp); - if (username == NULL) { - ast_log(LOG_ERROR,"cdr_odbc: Out of memory error.\n"); - res = -1; - goto out; - } - } - - tmp = ast_variable_retrieve(cfg,"global","password"); - if (tmp) { - password = strdup(tmp); - if (password == NULL) { - ast_log(LOG_ERROR,"cdr_odbc: Out of memory error.\n"); - res = -1; - goto out; - } - } - - tmp = ast_variable_retrieve(cfg,"global","loguniqueid"); - if (tmp) { - loguniqueid = ast_true(tmp); - if (loguniqueid) { - ast_log(LOG_DEBUG,"cdr_odbc: Logging uniqueid\n"); - } else { - ast_log(LOG_DEBUG,"cdr_odbc: Not logging uniqueid\n"); - } - } else { - ast_log(LOG_DEBUG,"cdr_odbc: Not logging uniqueid\n"); - loguniqueid = 0; - } - - tmp = ast_variable_retrieve(cfg,"global","usegmtime"); - if (tmp) { - usegmtime = ast_true(tmp); - if (usegmtime) { - ast_log(LOG_DEBUG,"cdr_odbc: Logging in GMT\n"); - } else { - ast_log(LOG_DEBUG,"cdr_odbc: Not logging in GMT\n"); - } - } else { - ast_log(LOG_DEBUG,"cdr_odbc: Not logging in GMT\n"); - usegmtime = 0; - } - - tmp = ast_variable_retrieve(cfg,"global","table"); - if (tmp == NULL) { - ast_log(LOG_WARNING,"cdr_odbc: table not specified. Assuming cdr\n"); - tmp = "cdr"; - } - table = strdup(tmp); - if (table == NULL) { - ast_log(LOG_ERROR,"cdr_odbc: Out of memory error.\n"); - res = -1; - goto out; - } - - if (option_verbose > 2) { - ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: dsn is %s\n",dsn); - if (username) - { - ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: username is %s\n",username); - ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: password is [secret]\n"); - } - else - ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: retreiving username and password from odbc config\n"); - ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: table is %s\n",table); - } - - res = odbc_init(); - if (res < 0) { - ast_log(LOG_ERROR, "cdr_odbc: Unable to connect to datasource: %s\n", dsn); - if (option_verbose > 2) { - ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: Unable to connect to datasource: %s\n", dsn); - } - } - res = ast_cdr_register(name, ast_module_info->description, odbc_log); - if (res) { - ast_log(LOG_ERROR, "cdr_odbc: Unable to register ODBC CDR handling\n"); - } -out: - if (cfg) - ast_config_destroy(cfg); - ast_mutex_unlock(&odbc_lock); - return res; -} - -static int odbc_do_query(void) -{ - int ODBC_res; - ODBC_res = SQLExecute(ODBC_stmt); - - if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error in Query %d\n", ODBC_res); - return -1; - } else { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query Successful!\n"); - connected = 1; - } - return 0; -} - -static int odbc_init(void) -{ - int ODBC_res; - - if (ODBC_env == SQL_NULL_HANDLE || connected == 0) { - ODBC_res = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &ODBC_env); - if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error AllocHandle\n"); - connected = 0; - return -1; - } - - ODBC_res = SQLSetEnvAttr(ODBC_env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); - - if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error SetEnv\n"); - SQLFreeHandle(SQL_HANDLE_ENV, ODBC_env); - ODBC_env = SQL_NULL_HANDLE; - connected = 0; - return -1; - } - - ODBC_res = SQLAllocHandle(SQL_HANDLE_DBC, ODBC_env, &ODBC_con); - - if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error AllocHDB %d\n", ODBC_res); - SQLFreeHandle(SQL_HANDLE_ENV, ODBC_env); - ODBC_env = SQL_NULL_HANDLE; - connected = 0; - return -1; - } - SQLSetConnectAttr(ODBC_con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)10, 0); - } - - /* Note that the username and password could be NULL here, but that is allowed in ODBC. - In this case, the default username and password will be used from odbc.conf */ - ODBC_res = SQLConnect(ODBC_con, (SQLCHAR*)dsn, SQL_NTS, (SQLCHAR*)username, SQL_NTS, (SQLCHAR*)password, SQL_NTS); - - if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error SQLConnect %d\n", ODBC_res); - SQLFreeHandle(SQL_HANDLE_DBC, ODBC_con); - ODBC_con = SQL_NULL_HANDLE; - SQLFreeHandle(SQL_HANDLE_ENV, ODBC_env); - ODBC_env = SQL_NULL_HANDLE; - connected = 0; - return -1; - } else { - if (option_verbose > 10) - ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Connected to %s\n", dsn); - connected = 1; - } - return 0; -} - -static int load_module(void) -{ - return odbc_load_module(); -} - -static int unload_module(void) -{ - return odbc_unload_module(); -} - -static int reload(void) -{ - odbc_unload_module(); - return odbc_load_module(); -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC CDR Backend", - .load = load_module, - .unload = unload_module, - .reload = reload, - ); diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c deleted file mode 100644 index a2144a712..000000000 --- a/cdr/cdr_pgsql.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2003 - 2006 - * - * Matthew D. Hardeman <mhardemn@papersoft.com> - * Adapted from the MySQL CDR logger originally by James Sharp - * - * Modified September 2003 - * Matthew D. Hardeman <mhardemn@papersoft.com> - * - * 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. - * - * 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. - */ - -/*! \file - * - * \brief PostgreSQL CDR logger - * - * \author Matthew D. Hardeman <mhardemn@papersoft.com> - * - * See also - * \arg \ref Config_cdr - * \arg http://www.postgresql.org/ - * \ingroup cdr_drivers - */ - -/*** MODULEINFO - <depend>pgsql</depend> - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <sys/types.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <time.h> - -#include <libpq-fe.h> - -#include "asterisk/config.h" -#include "asterisk/options.h" -#include "asterisk/channel.h" -#include "asterisk/cdr.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" -#include "asterisk.h" - -#define DATE_FORMAT "%Y-%m-%d %T" - -static char *name = "pgsql"; -static char *config = "cdr_pgsql.conf"; -static char *pghostname = NULL, *pgdbname = NULL, *pgdbuser = NULL, *pgpassword = NULL, *pgdbport = NULL, *table = NULL; -static int connected = 0; - -AST_MUTEX_DEFINE_STATIC(pgsql_lock); - -static PGconn *conn = NULL; - -static int pgsql_log(struct ast_cdr *cdr) -{ - struct tm tm; - time_t t = cdr->start.tv_sec; - char sqlcmd[2048] = "", timestr[128]; - char *pgerror; - PGresult *result; - - ast_mutex_lock(&pgsql_lock); - - ast_localtime(&t, &tm, NULL); - strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); - - if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) { - conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); - if (PQstatus(conn) != CONNECTION_BAD) { - connected = 1; - } else { - pgerror = PQerrorMessage(conn); - ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s. Calls will not be logged!\n", pghostname); - ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror); - PQfinish(conn); - conn = NULL; - } - } - - if (connected) { - char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL; - char *src=NULL, *dst=NULL, *uniqueid=NULL, *userfield=NULL; - int pgerr; - - /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */ - if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL) - PQescapeStringConn(conn, clid, cdr->clid, strlen(cdr->clid), &pgerr); - if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL) - PQescapeStringConn(conn, dcontext, cdr->dcontext, strlen(cdr->dcontext), &pgerr); - if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL) - PQescapeStringConn(conn, channel, cdr->channel, strlen(cdr->channel), &pgerr); - if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL) - PQescapeStringConn(conn, dstchannel, cdr->dstchannel, strlen(cdr->dstchannel), &pgerr); - if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL) - PQescapeStringConn(conn, lastapp, cdr->lastapp, strlen(cdr->lastapp), &pgerr); - if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL) - PQescapeStringConn(conn, lastdata, cdr->lastdata, strlen(cdr->lastdata), &pgerr); - if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL) - PQescapeStringConn(conn, uniqueid, cdr->uniqueid, strlen(cdr->uniqueid), &pgerr); - if ((userfield = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL) - PQescapeStringConn(conn, userfield, cdr->userfield, strlen(cdr->userfield), &pgerr); - if ((src = alloca(strlen(cdr->src) * 2 + 1)) != NULL) - PQescapeStringConn(conn, src, cdr->src, strlen(cdr->src), &pgerr); - if ((dst = alloca(strlen(cdr->dst) * 2 + 1)) != NULL) - PQescapeStringConn(conn, dst, cdr->dst, strlen(cdr->dst), &pgerr); - - /* Check for all alloca failures above at once */ - if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid) || (!userfield) || (!src) || (!dst)) { - ast_log(LOG_ERROR, "cdr_pgsql: Out of memory error (insert fails)\n"); - ast_mutex_unlock(&pgsql_lock); - return -1; - } - - if (option_debug > 1) - ast_log(LOG_DEBUG, "cdr_pgsql: inserting a CDR record.\n"); - - snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel," - "lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES" - " ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%ld,%ld,'%s',%ld,'%s','%s','%s')", - table, timestr, clid, src, dst, dcontext, channel, dstchannel, lastapp, lastdata, - cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode, uniqueid, userfield); - - if (option_debug > 2) - ast_log(LOG_DEBUG, "cdr_pgsql: SQL command executed: %s\n",sqlcmd); - - /* Test to be sure we're still connected... */ - /* If we're connected, and connection is working, good. */ - /* Otherwise, attempt reconnect. If it fails... sorry... */ - if (PQstatus(conn) == CONNECTION_OK) { - connected = 1; - } else { - ast_log(LOG_ERROR, "cdr_pgsql: Connection was lost... attempting to reconnect.\n"); - PQreset(conn); - if (PQstatus(conn) == CONNECTION_OK) { - ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n"); - connected = 1; - } else { - pgerror = PQerrorMessage(conn); - ast_log(LOG_ERROR, "cdr_pgsql: Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname); - ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror); - PQfinish(conn); - conn = NULL; - connected = 0; - ast_mutex_unlock(&pgsql_lock); - return -1; - } - } - result = PQexec(conn, sqlcmd); - if (PQresultStatus(result) != PGRES_COMMAND_OK) { - pgerror = PQresultErrorMessage(result); - ast_log(LOG_ERROR,"cdr_pgsql: Failed to insert call detail record into database!\n"); - ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror); - ast_log(LOG_ERROR,"cdr_pgsql: Connection may have been lost... attempting to reconnect.\n"); - PQreset(conn); - if (PQstatus(conn) == CONNECTION_OK) { - ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n"); - connected = 1; - PQclear(result); - result = PQexec(conn, sqlcmd); - if (PQresultStatus(result) != PGRES_COMMAND_OK) { - pgerror = PQresultErrorMessage(result); - ast_log(LOG_ERROR,"cdr_pgsql: HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n"); - ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror); - } - } - ast_mutex_unlock(&pgsql_lock); - PQclear(result); - return -1; - } - PQclear(result); - } - ast_mutex_unlock(&pgsql_lock); - return 0; -} - -static int my_unload_module(void) -{ - PQfinish(conn); - if (pghostname) - free(pghostname); - if (pgdbname) - free(pgdbname); - if (pgdbuser) - free(pgdbuser); - if (pgpassword) - free(pgpassword); - if (pgdbport) - free(pgdbport); - if (table) - free(table); - ast_cdr_unregister(name); - return 0; -} - -static int process_my_load_module(struct ast_config *cfg) -{ - struct ast_variable *var; - char *pgerror; - const char *tmp; - - if (!(var = ast_variable_browse(cfg, "global"))) - return 0; - - if (!(tmp = ast_variable_retrieve(cfg,"global","hostname"))) { - ast_log(LOG_WARNING,"PostgreSQL server hostname not specified. Assuming unix socket connection\n"); - tmp = ""; /* connect via UNIX-socket by default */ - } - - if (!(pghostname = ast_strdup(tmp))) - return -1; - - if (!(tmp = ast_variable_retrieve(cfg, "global", "dbname"))) { - ast_log(LOG_WARNING,"PostgreSQL database not specified. Assuming asterisk\n"); - tmp = "asteriskcdrdb"; - } - - if (!(pgdbname = ast_strdup(tmp))) - return -1; - - if (!(tmp = ast_variable_retrieve(cfg, "global", "user"))) { - ast_log(LOG_WARNING,"PostgreSQL database user not specified. Assuming asterisk\n"); - tmp = "asterisk"; - } - - if (!(pgdbuser = ast_strdup(tmp))) - return -1; - - if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) { - ast_log(LOG_WARNING,"PostgreSQL database password not specified. Assuming blank\n"); - tmp = ""; - } - - if (!(pgpassword = ast_strdup(tmp))) - return -1; - - if (!(tmp = ast_variable_retrieve(cfg,"global","port"))) { - ast_log(LOG_WARNING,"PostgreSQL database port not specified. Using default 5432.\n"); - tmp = "5432"; - } - - if (!(pgdbport = ast_strdup(tmp))) - return -1; - - if (!(tmp = ast_variable_retrieve(cfg, "global", "table"))) { - ast_log(LOG_WARNING,"CDR table not specified. Assuming cdr\n"); - tmp = "cdr"; - } - - if (!(table = ast_strdup(tmp))) - return -1; - - if (option_debug) { - if (ast_strlen_zero(pghostname)) - ast_log(LOG_DEBUG, "cdr_pgsql: using default unix socket\n"); - else - ast_log(LOG_DEBUG, "cdr_pgsql: got hostname of %s\n", pghostname); - ast_log(LOG_DEBUG, "cdr_pgsql: got port of %s\n", pgdbport); - ast_log(LOG_DEBUG, "cdr_pgsql: got user of %s\n", pgdbuser); - ast_log(LOG_DEBUG, "cdr_pgsql: got dbname of %s\n", pgdbname); - ast_log(LOG_DEBUG, "cdr_pgsql: got password of %s\n", pgpassword); - ast_log(LOG_DEBUG, "cdr_pgsql: got sql table name of %s\n", table); - } - - conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); - if (PQstatus(conn) != CONNECTION_BAD) { - if (option_debug) - ast_log(LOG_DEBUG, "Successfully connected to PostgreSQL database.\n"); - connected = 1; - } else { - pgerror = PQerrorMessage(conn); - ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s. CALLS WILL NOT BE LOGGED!!\n", pghostname); - ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror); - connected = 0; - } - - return ast_cdr_register(name, ast_module_info->description, pgsql_log); -} - -static int my_load_module(void) -{ - struct ast_config *cfg; - int res; - - if (!(cfg = ast_config_load(config))) { - ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config); - return AST_MODULE_LOAD_DECLINE; - } - - res = process_my_load_module(cfg); - ast_config_destroy(cfg); - - return res; -} - -static int load_module(void) -{ - return my_load_module(); -} - -static int unload_module(void) -{ - return my_unload_module(); -} - -static int reload(void) -{ - int res; - ast_mutex_lock(&pgsql_lock); - my_unload_module(); - res = my_load_module(); - ast_mutex_unlock(&pgsql_lock); - return res; -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "PostgreSQL CDR Backend", - .load = load_module, - .unload = unload_module, - .reload = reload, - ); diff --git a/cdr/cdr_radius.c b/cdr/cdr_radius.c deleted file mode 100644 index 6d890e764..000000000 --- a/cdr/cdr_radius.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * 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. - * - * 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. - */ - -/*! \file - * - * \brief RADIUS CDR Support - * \author Philippe Sultan - * - * \arg See also \ref AstCDR - * \ingroup cdr_drivers - */ - -/*** MODULEINFO - <depend>radius</depend> - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Rev$") - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <time.h> -#include <sys/types.h> -#include <radiusclient-ng.h> - -#include "asterisk/channel.h" -#include "asterisk/cdr.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" -#include "asterisk/utils.h" -#include "asterisk/options.h" - -/*! ISO 8601 standard format */ -#define DATE_FORMAT "%Y-%m-%d %T %z" - -#define VENDOR_CODE 22736 - -enum { - PW_AST_ACCT_CODE = 101, - PW_AST_SRC = 102, - PW_AST_DST = 103, - PW_AST_DST_CTX = 104, - PW_AST_CLID = 105, - PW_AST_CHAN = 106, - PW_AST_DST_CHAN = 107, - PW_AST_LAST_APP = 108, - PW_AST_LAST_DATA = 109, - PW_AST_START_TIME = 110, - PW_AST_ANSWER_TIME = 111, - PW_AST_END_TIME = 112, - PW_AST_DURATION = 113, - PW_AST_BILL_SEC = 114, - PW_AST_DISPOSITION = 115, - PW_AST_AMA_FLAGS = 116, - PW_AST_UNIQUE_ID = 117, - PW_AST_USER_FIELD = 118 -}; - -enum { - /*! Log dates and times in UTC */ - RADIUS_FLAG_USEGMTIME = (1 << 0), - /*! Log Unique ID */ - RADIUS_FLAG_LOGUNIQUEID = (1 << 1), - /*! Log User Field */ - RADIUS_FLAG_LOGUSERFIELD = (1 << 2) -}; - -static char *desc = "RADIUS CDR Backend"; -static char *name = "radius"; -static char *cdr_config = "cdr.conf"; - -static char radiuscfg[PATH_MAX] = "/etc/radiusclient-ng/radiusclient.conf"; - -static struct ast_flags global_flags = { RADIUS_FLAG_USEGMTIME | RADIUS_FLAG_LOGUNIQUEID | RADIUS_FLAG_LOGUSERFIELD }; - -static rc_handle *rh = NULL; - -static int build_radius_record(VALUE_PAIR **send, struct ast_cdr *cdr) -{ - int recordtype = PW_STATUS_STOP; - struct tm tm; - char timestr[128]; - char *tmp; - - if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0)) - return -1; - - /* Account code */ - if (!rc_avpair_add(rh, send, PW_AST_ACCT_CODE, &cdr->accountcode, strlen(cdr->accountcode), VENDOR_CODE)) - return -1; - - /* Source */ - if (!rc_avpair_add(rh, send, PW_AST_SRC, &cdr->src, strlen(cdr->src), VENDOR_CODE)) - return -1; - - /* Destination */ - if (!rc_avpair_add(rh, send, PW_AST_DST, &cdr->dst, strlen(cdr->dst), VENDOR_CODE)) - return -1; - - /* Destination context */ - if (!rc_avpair_add(rh, send, PW_AST_DST_CTX, &cdr->dcontext, strlen(cdr->dcontext), VENDOR_CODE)) - return -1; - - /* Caller ID */ - if (!rc_avpair_add(rh, send, PW_AST_CLID, &cdr->clid, strlen(cdr->clid), VENDOR_CODE)) - return -1; - - /* Channel */ - if (!rc_avpair_add(rh, send, PW_AST_CHAN, &cdr->channel, strlen(cdr->channel), VENDOR_CODE)) - return -1; - - /* Destination Channel */ - if (!rc_avpair_add(rh, send, PW_AST_DST_CHAN, &cdr->dstchannel, strlen(cdr->dstchannel), VENDOR_CODE)) - return -1; - - /* Last Application */ - if (!rc_avpair_add(rh, send, PW_AST_LAST_APP, &cdr->lastapp, strlen(cdr->lastapp), VENDOR_CODE)) - return -1; - - /* Last Data */ - if (!rc_avpair_add(rh, send, PW_AST_LAST_DATA, &cdr->lastdata, strlen(cdr->lastdata), VENDOR_CODE)) - return -1; - - - /* Start Time */ - if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME)) - gmtime_r(&(cdr->start.tv_sec), &tm); - else - ast_localtime(&(cdr->start.tv_sec), &tm, NULL); - strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); - if (!rc_avpair_add(rh, send, PW_AST_START_TIME, timestr, strlen(timestr), VENDOR_CODE)) - return -1; - - /* Answer Time */ - if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME)) - gmtime_r(&(cdr->answer.tv_sec), &tm); - else - ast_localtime(&(cdr->answer.tv_sec), &tm, NULL); - strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); - if (!rc_avpair_add(rh, send, PW_AST_ANSWER_TIME, timestr, strlen(timestr), VENDOR_CODE)) - return -1; - - /* End Time */ - if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME)) - gmtime_r(&(cdr->end.tv_sec), &tm); - else - ast_localtime(&(cdr->end.tv_sec), &tm, NULL); - strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); - if (!rc_avpair_add(rh, send, PW_AST_END_TIME, timestr, strlen(timestr), VENDOR_CODE)) - return -1; - - /* Duration */ - if (!rc_avpair_add(rh, send, PW_AST_DURATION, &cdr->duration, 0, VENDOR_CODE)) - return -1; - - /* Billable seconds */ - if (!rc_avpair_add(rh, send, PW_AST_BILL_SEC, &cdr->billsec, 0, VENDOR_CODE)) - return -1; - - /* Disposition */ - tmp = ast_cdr_disp2str(cdr->disposition); - if (!rc_avpair_add(rh, send, PW_AST_DISPOSITION, tmp, strlen(tmp), VENDOR_CODE)) - return -1; - - /* AMA Flags */ - tmp = ast_cdr_flags2str(cdr->amaflags); - if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, tmp, strlen(tmp), VENDOR_CODE)) - return -1; - - if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) { - /* Unique ID */ - if (!rc_avpair_add(rh, send, PW_AST_UNIQUE_ID, &cdr->uniqueid, strlen(cdr->uniqueid), VENDOR_CODE)) - return -1; - } - - if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUSERFIELD)) { - /* append the user field */ - if (!rc_avpair_add(rh, send, PW_AST_USER_FIELD, &cdr->userfield, strlen(cdr->userfield), VENDOR_CODE)) - return -1; - } - - /* Setting Acct-Session-Id & User-Name attributes for proper generation - of Acct-Unique-Session-Id on server side */ - /* Channel */ - if (!rc_avpair_add(rh, send, PW_USER_NAME, &cdr->channel, strlen(cdr->channel), 0)) - return -1; - - /* Unique ID */ - if (!rc_avpair_add(rh, send, PW_ACCT_SESSION_ID, &cdr->uniqueid, strlen(cdr->uniqueid), 0)) - return -1; - - return 0; -} - -static int radius_log(struct ast_cdr *cdr) -{ - int result = ERROR_RC; - VALUE_PAIR *send = NULL; - - if (build_radius_record(&send, cdr)) { - if (option_debug) - ast_log(LOG_DEBUG, "Unable to create RADIUS record. CDR not recorded!\n"); - return result; - } - - result = rc_acct(rh, 0, send); - if (result != OK_RC) - ast_log(LOG_ERROR, "Failed to record Radius CDR record!\n"); - - return result; -} - -static int unload_module(void) -{ - ast_cdr_unregister(name); - return 0; -} - -static int load_module(void) -{ - struct ast_config *cfg; - int res; - const char *tmp; - - if ((cfg = ast_config_load(cdr_config))) { - ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME); - ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguniqueid")), RADIUS_FLAG_LOGUNIQUEID); - ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguserfield")), RADIUS_FLAG_LOGUSERFIELD); - if ((tmp = ast_variable_retrieve(cfg, "radius", "radiuscfg"))) - ast_copy_string(radiuscfg, tmp, sizeof(radiuscfg)); - ast_config_destroy(cfg); - } else - return AST_MODULE_LOAD_DECLINE; - - /* start logging */ - rc_openlog("asterisk"); - - /* read radiusclient-ng config file */ - if (!(rh = rc_read_config(radiuscfg))) { - ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg); - return AST_MODULE_LOAD_DECLINE; - } - - /* read radiusclient-ng dictionaries */ - if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) { - ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n"); - return AST_MODULE_LOAD_DECLINE; - } - - res = ast_cdr_register(name, desc, radius_log); - return AST_MODULE_LOAD_SUCCESS; -} - -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "RADIUS CDR Backend"); diff --git a/cdr/cdr_sqlite.c b/cdr/cdr_sqlite.c deleted file mode 100644 index 5aa8a5154..000000000 --- a/cdr/cdr_sqlite.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2004 - 2005, Holger Schurig - * - * - * Ideas taken from other cdr_*.c files - * - * 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. - * - * 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. - */ - -/*! \file - * - * \brief Store CDR records in a SQLite database. - * - * \author Holger Schurig <hs4233@mail.mn-solutions.de> - * - * See also - * \arg \ref Config_cdr - * \arg http://www.sqlite.org/ - * - * Creates the database and table on-the-fly - * \ingroup cdr_drivers - */ - -/*** MODULEINFO - <depend>sqlite</depend> - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <sys/types.h> -#include <unistd.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <sqlite.h> - -#include "asterisk/channel.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" -#include "asterisk/utils.h" - -#define LOG_UNIQUEID 0 -#define LOG_USERFIELD 0 - -/* When you change the DATE_FORMAT, be sure to change the CHAR(19) below to something else */ -#define DATE_FORMAT "%Y-%m-%d %T" - -static char *name = "sqlite"; -static sqlite* db = NULL; - -AST_MUTEX_DEFINE_STATIC(sqlite_lock); - -/*! \brief SQL table format */ -static char sql_create_table[] = "CREATE TABLE cdr (" -" AcctId INTEGER PRIMARY KEY," -" clid VARCHAR(80)," -" src VARCHAR(80)," -" dst VARCHAR(80)," -" dcontext VARCHAR(80)," -" channel VARCHAR(80)," -" dstchannel VARCHAR(80)," -" lastapp VARCHAR(80)," -" lastdata VARCHAR(80)," -" start CHAR(19)," -" answer CHAR(19)," -" end CHAR(19)," -" duration INTEGER," -" billsec INTEGER," -" disposition INTEGER," -" amaflags INTEGER," -" accountcode VARCHAR(20)" -#if LOG_UNIQUEID -" ,uniqueid VARCHAR(32)" -#endif -#if LOG_USERFIELD -" ,userfield VARCHAR(255)" -#endif -");"; - -static int sqlite_log(struct ast_cdr *cdr) -{ - int res = 0; - char *zErr = 0; - struct tm tm; - time_t t; - char startstr[80], answerstr[80], endstr[80]; - int count; - - ast_mutex_lock(&sqlite_lock); - - t = cdr->start.tv_sec; - ast_localtime(&t, &tm, NULL); - strftime(startstr, sizeof(startstr), DATE_FORMAT, &tm); - - t = cdr->answer.tv_sec; - ast_localtime(&t, &tm, NULL); - strftime(answerstr, sizeof(answerstr), DATE_FORMAT, &tm); - - t = cdr->end.tv_sec; - ast_localtime(&t, &tm, NULL); - strftime(endstr, sizeof(endstr), DATE_FORMAT, &tm); - - for(count=0; count<5; count++) { - res = sqlite_exec_printf(db, - "INSERT INTO cdr (" - "clid,src,dst,dcontext," - "channel,dstchannel,lastapp,lastdata, " - "start,answer,end," - "duration,billsec,disposition,amaflags, " - "accountcode" -# if LOG_UNIQUEID - ",uniqueid" -# endif -# if LOG_USERFIELD - ",userfield" -# endif - ") VALUES (" - "'%q', '%q', '%q', '%q', " - "'%q', '%q', '%q', '%q', " - "'%q', '%q', '%q', " - "%d, %d, %d, %d, " - "'%q'" -# if LOG_UNIQUEID - ",'%q'" -# endif -# if LOG_USERFIELD - ",'%q'" -# endif - ")", NULL, NULL, &zErr, - cdr->clid, cdr->src, cdr->dst, cdr->dcontext, - cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata, - startstr, answerstr, endstr, - cdr->duration, cdr->billsec, cdr->disposition, cdr->amaflags, - cdr->accountcode -# if LOG_UNIQUEID - ,cdr->uniqueid -# endif -# if LOG_USERFIELD - ,cdr->userfield -# endif - ); - if (res != SQLITE_BUSY && res != SQLITE_LOCKED) - break; - usleep(200); - } - - if (zErr) { - ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr); - free(zErr); - } - - ast_mutex_unlock(&sqlite_lock); - return res; -} - -static int unload_module(void) -{ - if (db) - sqlite_close(db); - ast_cdr_unregister(name); - return 0; -} - -static int load_module(void) -{ - char *zErr; - char fn[PATH_MAX]; - int res; - - /* is the database there? */ - snprintf(fn, sizeof(fn), "%s/cdr.db", ast_config_AST_LOG_DIR); - db = sqlite_open(fn, 0660, &zErr); - if (!db) { - ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr); - free(zErr); - return -1; - } - - /* is the table there? */ - res = sqlite_exec(db, "SELECT COUNT(AcctId) FROM cdr;", NULL, NULL, NULL); - if (res) { - res = sqlite_exec(db, sql_create_table, NULL, NULL, &zErr); - if (res) { - ast_log(LOG_ERROR, "cdr_sqlite: Unable to create table 'cdr': %s\n", zErr); - free(zErr); - goto err; - } - - /* TODO: here we should probably create an index */ - } - - res = ast_cdr_register(name, ast_module_info->description, sqlite_log); - if (res) { - ast_log(LOG_ERROR, "Unable to register SQLite CDR handling\n"); - return -1; - } - return 0; - -err: - if (db) - sqlite_close(db); - return -1; -} - -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SQLite CDR Backend"); diff --git a/cdr/cdr_tds.c b/cdr/cdr_tds.c deleted file mode 100644 index 4e44e4ee1..000000000 --- a/cdr/cdr_tds.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2004 - 2006, Digium, Inc. - * - * 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. - * - * 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. - */ - -/*! \file - * - * \brief FreeTDS CDR logger - * - * See also - * \arg \ref Config_cdr - * \arg http://www.freetds.org/ - * \ingroup cdr_drivers - */ - -/*! \verbatim - * - * Table Structure for `cdr` - * - * Created on: 05/20/2004 16:16 - * Last changed on: 07/27/2004 20:01 - -CREATE TABLE [dbo].[cdr] ( - [accountcode] [varchar] (20) NULL , - [src] [varchar] (80) NULL , - [dst] [varchar] (80) NULL , - [dcontext] [varchar] (80) NULL , - [clid] [varchar] (80) NULL , - [channel] [varchar] (80) NULL , - [dstchannel] [varchar] (80) NULL , - [lastapp] [varchar] (80) NULL , - [lastdata] [varchar] (80) NULL , - [start] [datetime] NULL , - [answer] [datetime] NULL , - [end] [datetime] NULL , - [duration] [int] NULL , - [billsec] [int] NULL , - [disposition] [varchar] (20) NULL , - [amaflags] [varchar] (16) NULL , - [uniqueid] [varchar] (32) NULL , - [userfield] [varchar] (256) NULL -) ON [PRIMARY] - -\endverbatim - -*/ - -/*** MODULEINFO - <depend>freetds</depend> - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <sys/types.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <time.h> -#include <math.h> - -#include <tds.h> -#include <tdsconvert.h> -#include <ctype.h> - -#include "asterisk/config.h" -#include "asterisk/options.h" -#include "asterisk/channel.h" -#include "asterisk/cdr.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" - -#ifdef FREETDS_PRE_0_62 -#warning "You have older TDS, you should upgrade!" -#endif - -#define DATE_FORMAT "%Y/%m/%d %T" - -static char *name = "mssql"; -static char *config = "cdr_tds.conf"; - -static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *charset = NULL, *language = NULL; -static char *table = NULL; - -static int connected = 0; -static int has_userfield = 0; - -AST_MUTEX_DEFINE_STATIC(tds_lock); - -static TDSSOCKET *tds; -static TDSLOGIN *login; -static TDSCONTEXT *context; - -static char *anti_injection(const char *, int); -static void get_date(char *, size_t, struct timeval); - -static int mssql_connect(void); -static int mssql_disconnect(void); - -static int tds_log(struct ast_cdr *cdr) -{ - char sqlcmd[2048], start[80], answer[80], end[80]; - char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid, *userfield = NULL; - int res = 0; - int retried = 0; -#ifdef FREETDS_PRE_0_62 - TDS_INT result_type; -#endif - - ast_mutex_lock(&tds_lock); - - memset(sqlcmd, 0, 2048); - - accountcode = anti_injection(cdr->accountcode, 20); - src = anti_injection(cdr->src, 80); - dst = anti_injection(cdr->dst, 80); - dcontext = anti_injection(cdr->dcontext, 80); - clid = anti_injection(cdr->clid, 80); - channel = anti_injection(cdr->channel, 80); - dstchannel = anti_injection(cdr->dstchannel, 80); - lastapp = anti_injection(cdr->lastapp, 80); - lastdata = anti_injection(cdr->lastdata, 80); - uniqueid = anti_injection(cdr->uniqueid, 32); - - if (has_userfield) { - userfield = anti_injection(cdr->userfield, AST_MAX_USER_FIELD); - } - - get_date(start, sizeof(start), cdr->start); - get_date(answer, sizeof(answer), cdr->answer); - get_date(end, sizeof(end), cdr->end); - - if (has_userfield) { - snprintf( - sqlcmd, - sizeof(sqlcmd), - "INSERT INTO %s " - "(" - "accountcode, " - "src, " - "dst, " - "dcontext, " - "clid, " - "channel, " - "dstchannel, " - "lastapp, " - "lastdata, " - "start, " - "answer, " - "[end], " - "duration, " - "billsec, " - "disposition, " - "amaflags, " - "uniqueid, " - "userfield" - ") " - "VALUES " - "(" - "'%s', " /* accountcode */ - "'%s', " /* src */ - "'%s', " /* dst */ - "'%s', " /* dcontext */ - "'%s', " /* clid */ - "'%s', " /* channel */ - "'%s', " /* dstchannel */ - "'%s', " /* lastapp */ - "'%s', " /* lastdata */ - "%s, " /* start */ - "%s, " /* answer */ - "%s, " /* end */ - "%ld, " /* duration */ - "%ld, " /* billsec */ - "'%s', " /* disposition */ - "'%s', " /* amaflags */ - "'%s', " /* uniqueid */ - "'%s'" /* userfield */ - ")", - table, - accountcode, - src, - dst, - dcontext, - clid, - channel, - dstchannel, - lastapp, - lastdata, - start, - answer, - end, - cdr->duration, - cdr->billsec, - ast_cdr_disp2str(cdr->disposition), - ast_cdr_flags2str(cdr->amaflags), - uniqueid, - userfield - ); - } else { - snprintf( - sqlcmd, - sizeof(sqlcmd), - "INSERT INTO %s " - "(" - "accountcode, " - "src, " - "dst, " - "dcontext, " - "clid, " - "channel, " - "dstchannel, " - "lastapp, " - "lastdata, " - "start, " - "answer, " - "[end], " - "duration, " - "billsec, " - "disposition, " - "amaflags, " - "uniqueid" - ") " - "VALUES " - "(" - "'%s', " /* accountcode */ - "'%s', " /* src */ - "'%s', " /* dst */ - "'%s', " /* dcontext */ - "'%s', " /* clid */ - "'%s', " /* channel */ - "'%s', " /* dstchannel */ - "'%s', " /* lastapp */ - "'%s', " /* lastdata */ - "%s, " /* start */ - "%s, " /* answer */ - "%s, " /* end */ - "%ld, " /* duration */ - "%ld, " /* billsec */ - "'%s', " /* disposition */ - "'%s', " /* amaflags */ - "'%s'" /* uniqueid */ - ")", - table, - accountcode, - src, - dst, - dcontext, - clid, - channel, - dstchannel, - lastapp, - lastdata, - start, - answer, - end, - cdr->duration, - cdr->billsec, - ast_cdr_disp2str(cdr->disposition), - ast_cdr_flags2str(cdr->amaflags), - uniqueid - ); - } - - do { - if (!connected) { - if (mssql_connect()) - ast_log(LOG_ERROR, "Failed to reconnect to SQL database.\n"); - else - ast_log(LOG_WARNING, "Reconnected to SQL database.\n"); - - retried = 1; /* note that we have now tried */ - } - -#ifdef FREETDS_PRE_0_62 - if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) -#else - if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) -#endif - { - ast_log(LOG_ERROR, "Failed to insert Call Data Record into SQL database.\n"); - - mssql_disconnect(); /* this is ok even if we are already disconnected */ - } - } while (!connected && !retried); - - free(accountcode); - free(src); - free(dst); - free(dcontext); - free(clid); - free(channel); - free(dstchannel); - free(lastapp); - free(lastdata); - free(uniqueid); - if (userfield) { - free(userfield); - } - - ast_mutex_unlock(&tds_lock); - - return res; -} - -static char *anti_injection(const char *str, int len) -{ - /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */ - - char *buf; - char *buf_ptr, *srh_ptr; - char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"}; - int idx; - - if ((buf = malloc(len + 1)) == NULL) - { - ast_log(LOG_ERROR, "cdr_tds: Out of memory error\n"); - return NULL; - } - memset(buf, 0, len); - - buf_ptr = buf; - - /* Escape single quotes */ - for (; *str && strlen(buf) < len; str++) - { - if (*str == '\'') - *buf_ptr++ = '\''; - *buf_ptr++ = *str; - } - *buf_ptr = '\0'; - - /* Erase known bad input */ - for (idx=0; *known_bad[idx]; idx++) - { - while((srh_ptr = strcasestr(buf, known_bad[idx]))) - { - memmove(srh_ptr, srh_ptr+strlen(known_bad[idx]), strlen(srh_ptr+strlen(known_bad[idx]))+1); - } - } - - return buf; -} - -static void get_date(char *dateField, size_t length, struct timeval tv) -{ - struct tm tm; - time_t t; - char buf[80]; - - /* To make sure we have date variable if not insert null to SQL */ - if (!ast_tvzero(tv)) - { - t = tv.tv_sec; - ast_localtime(&t, &tm, NULL); - strftime(buf, sizeof(buf), DATE_FORMAT, &tm); - snprintf(dateField, length, "'%s'", buf); - } - else - { - ast_copy_string(dateField, "null", length); - } -} - -static int mssql_disconnect(void) -{ - if (tds) { - tds_free_socket(tds); - tds = NULL; - } - - if (context) { - tds_free_context(context); - context = NULL; - } - - if (login) { - tds_free_login(login); - login = NULL; - } - - connected = 0; - - return 0; -} - -static int mssql_connect(void) -{ -#if (defined(FREETDS_0_63) || defined(FREETDS_0_64)) - TDSCONNECTION *connection = NULL; -#else - TDSCONNECTINFO *connection = NULL; -#endif - char query[512]; - - /* Connect to M$SQL Server */ - if (!(login = tds_alloc_login())) - { - ast_log(LOG_ERROR, "tds_alloc_login() failed.\n"); - return -1; - } - - tds_set_server(login, hostname); - tds_set_user(login, dbuser); - tds_set_passwd(login, password); - tds_set_app(login, "TSQL"); - tds_set_library(login, "TDS-Library"); -#ifndef FREETDS_PRE_0_62 - tds_set_client_charset(login, charset); -#endif - tds_set_language(login, language); - tds_set_packet(login, 512); - tds_set_version(login, 7, 0); - -#ifdef FREETDS_0_64 - if (!(context = tds_alloc_context(NULL))) -#else - if (!(context = tds_alloc_context())) -#endif - { - ast_log(LOG_ERROR, "tds_alloc_context() failed.\n"); - goto connect_fail; - } - - if (!(tds = tds_alloc_socket(context, 512))) { - ast_log(LOG_ERROR, "tds_alloc_socket() failed.\n"); - goto connect_fail; - } - - tds_set_parent(tds, NULL); - connection = tds_read_config_info(tds, login, context->locale); - if (!connection) - { - ast_log(LOG_ERROR, "tds_read_config() failed.\n"); - goto connect_fail; - } - - if (tds_connect(tds, connection) == TDS_FAIL) - { - ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n"); - tds = NULL; /* freed by tds_connect() on error */ -#if (defined(FREETDS_0_63) || defined(FREETDS_0_64)) - tds_free_connection(connection); -#else - tds_free_connect(connection); -#endif - connection = NULL; - goto connect_fail; - } -#if (defined(FREETDS_0_63) || defined(FREETDS_0_64)) - tds_free_connection(connection); -#else - tds_free_connect(connection); -#endif - connection = NULL; - - snprintf(query, sizeof(query), "USE %s", dbname); -#ifdef FREETDS_PRE_0_62 - if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) -#else - if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) -#endif - { - ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname); - goto connect_fail; - } - - snprintf(query, sizeof(query), "SELECT 1 FROM %s", table); -#ifdef FREETDS_PRE_0_62 - if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) -#else - if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) -#endif - { - ast_log(LOG_ERROR, "Could not find table '%s' in database '%s'\n", table, dbname); - goto connect_fail; - } - - has_userfield = 1; - snprintf(query, sizeof(query), "SELECT userfield FROM %s WHERE 1 = 0", table); -#ifdef FREETDS_PRE_0_62 - if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) -#else - if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) -#endif - { - ast_log(LOG_NOTICE, "Unable to find 'userfield' column in table '%s'\n", table); - has_userfield = 0; - } - - connected = 1; - return 0; - -connect_fail: - mssql_disconnect(); - return -1; -} - -static int tds_unload_module(void) -{ - mssql_disconnect(); - - ast_cdr_unregister(name); - - if (hostname) free(hostname); - if (dbname) free(dbname); - if (dbuser) free(dbuser); - if (password) free(password); - if (charset) free(charset); - if (language) free(language); - if (table) free(table); - - return 0; -} - -static int tds_load_module(void) -{ - int res = 0; - struct ast_config *cfg; - struct ast_variable *var; - const char *ptr = NULL; -#ifdef FREETDS_PRE_0_62 - TDS_INT result_type; -#endif - - cfg = ast_config_load(config); - if (!cfg) { - ast_log(LOG_NOTICE, "Unable to load config for MSSQL CDR's: %s\n", config); - return 0; - } - - var = ast_variable_browse(cfg, "global"); - if (!var) /* nothing configured */ { - ast_config_destroy(cfg); - return 0; - } - - ptr = ast_variable_retrieve(cfg, "global", "hostname"); - if (ptr) - hostname = strdup(ptr); - else - ast_log(LOG_ERROR,"Database server hostname not specified.\n"); - - ptr = ast_variable_retrieve(cfg, "global", "dbname"); - if (ptr) - dbname = strdup(ptr); - else - ast_log(LOG_ERROR,"Database dbname not specified.\n"); - - ptr = ast_variable_retrieve(cfg, "global", "user"); - if (ptr) - dbuser = strdup(ptr); - else - ast_log(LOG_ERROR,"Database dbuser not specified.\n"); - - ptr = ast_variable_retrieve(cfg, "global", "password"); - if (ptr) - password = strdup(ptr); - else - ast_log(LOG_ERROR,"Database password not specified.\n"); - - ptr = ast_variable_retrieve(cfg, "global", "charset"); - if (ptr) - charset = strdup(ptr); - else - charset = strdup("iso_1"); - - ptr = ast_variable_retrieve(cfg, "global", "language"); - if (ptr) - language = strdup(ptr); - else - language = strdup("us_english"); - - ptr = ast_variable_retrieve(cfg,"global","table"); - if (ptr == NULL) { - ast_log(LOG_DEBUG,"cdr_tds: table not specified. Assuming cdr\n"); - ptr = "cdr"; - } - table = strdup(ptr); - - ast_config_destroy(cfg); - - mssql_connect(); - - /* Register MSSQL CDR handler */ - res = ast_cdr_register(name, ast_module_info->description, tds_log); - if (res) - { - ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n"); - } - - return res; -} - -static int reload(void) -{ - tds_unload_module(); - return tds_load_module(); -} - -static int load_module(void) -{ - if(!tds_load_module()) - return AST_MODULE_LOAD_DECLINE; - else - return AST_MODULE_LOAD_SUCCESS; -} - -static int unload_module(void) -{ - return tds_unload_module(); -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MSSQL CDR Backend", - .load = load_module, - .unload = unload_module, - .reload = reload, - ); |