mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-17 15:29:05 +00:00
Merged revisions 126226,126513 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk ........ r126226 | seanbright | 2008-06-28 17:28:16 -0400 (Sat, 28 Jun 2008) | 8 lines Merge in changes from my cdr-tds-conversion branch. This changes the internal implementation from using the volatile libtds, to using the db-lib front end. The unintended side effect of this is that we support (at least) versions 0.62 through 0.82 of the FreeTDS distribution without any #ifdef ugliness. (closes issue #12844) Reported by: jcollie ........ r126513 | seanbright | 2008-06-30 07:57:42 -0400 (Mon, 30 Jun 2008) | 4 lines Cast a few more strings to char *, so that we can compile cleanly against FreeTDS 0.60. Update the docs to reflect that we can now compile and run against all modern releases of FreeTDS (0.60 through 0.82) ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.6.0@127397 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -142,6 +142,9 @@ CDR:
|
|||||||
possible values the systemname prefix could be. In the past, if the
|
possible values the systemname prefix could be. In the past, if the
|
||||||
systemname was too long, the uniqueid would have been truncated.
|
systemname was too long, the uniqueid would have been truncated.
|
||||||
|
|
||||||
|
* The cdr_tds module now supports all versions of FreeTDS that contain
|
||||||
|
the db-lib frontend.
|
||||||
|
|
||||||
Formats:
|
Formats:
|
||||||
|
|
||||||
* format_wav: The GAIN preprocessor definition and source code that used it
|
* format_wav: The GAIN preprocessor definition and source code that used it
|
||||||
|
|||||||
438
cdr/cdr_tds.c
438
cdr/cdr_tds.c
@@ -66,54 +66,49 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include <tds.h>
|
|
||||||
#include <tdsconvert.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "asterisk/config.h"
|
#include "asterisk/config.h"
|
||||||
#include "asterisk/channel.h"
|
#include "asterisk/channel.h"
|
||||||
#include "asterisk/cdr.h"
|
#include "asterisk/cdr.h"
|
||||||
#include "asterisk/module.h"
|
#include "asterisk/module.h"
|
||||||
|
|
||||||
#ifdef FREETDS_PRE_0_62
|
#include <sqlfront.h>
|
||||||
#warning "You have older TDS, you should upgrade!"
|
#include <sybdb.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DATE_FORMAT "%Y/%m/%d %T"
|
#define DATE_FORMAT "%Y/%m/%d %T"
|
||||||
|
|
||||||
static char *name = "mssql";
|
static char *name = "FreeTDS (MSSQL)";
|
||||||
static char *config = "cdr_tds.conf";
|
static char *config = "cdr_tds.conf";
|
||||||
|
|
||||||
static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *charset = NULL, *language = NULL;
|
struct cdr_tds_config {
|
||||||
static char *table = NULL;
|
AST_DECLARE_STRING_FIELDS(
|
||||||
|
AST_STRING_FIELD(hostname);
|
||||||
static int connected = 0;
|
AST_STRING_FIELD(database);
|
||||||
|
AST_STRING_FIELD(username);
|
||||||
|
AST_STRING_FIELD(password);
|
||||||
|
AST_STRING_FIELD(table);
|
||||||
|
AST_STRING_FIELD(charset);
|
||||||
|
AST_STRING_FIELD(language);
|
||||||
|
);
|
||||||
|
DBPROCESS *dbproc;
|
||||||
|
unsigned int connected:1;
|
||||||
|
};
|
||||||
|
|
||||||
AST_MUTEX_DEFINE_STATIC(tds_lock);
|
AST_MUTEX_DEFINE_STATIC(tds_lock);
|
||||||
|
|
||||||
static TDSSOCKET *tds;
|
static struct cdr_tds_config *settings;
|
||||||
static TDSLOGIN *login;
|
|
||||||
static TDSCONTEXT *context;
|
|
||||||
|
|
||||||
static char *anti_injection(const char *, int);
|
static char *anti_injection(const char *, int);
|
||||||
static void get_date(char *, struct timeval);
|
static void get_date(char *, size_t len, struct timeval);
|
||||||
|
|
||||||
static int mssql_connect(void);
|
static int mssql_connect(void);
|
||||||
static int mssql_disconnect(void);
|
static int mssql_disconnect(void);
|
||||||
|
|
||||||
static int tds_log(struct ast_cdr *cdr)
|
static int tds_log(struct ast_cdr *cdr)
|
||||||
{
|
{
|
||||||
char sqlcmd[2048], start[80], answer[80], end[80];
|
char start[80], answer[80], end[80];
|
||||||
char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid;
|
char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid;
|
||||||
int res = 0;
|
RETCODE erc;
|
||||||
int retried = 0;
|
int res = -1;
|
||||||
#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);
|
accountcode = anti_injection(cdr->accountcode, 20);
|
||||||
src = anti_injection(cdr->src, 80);
|
src = anti_injection(cdr->src, 80);
|
||||||
@@ -126,12 +121,21 @@ static int tds_log(struct ast_cdr *cdr)
|
|||||||
lastdata = anti_injection(cdr->lastdata, 80);
|
lastdata = anti_injection(cdr->lastdata, 80);
|
||||||
uniqueid = anti_injection(cdr->uniqueid, 32);
|
uniqueid = anti_injection(cdr->uniqueid, 32);
|
||||||
|
|
||||||
get_date(start, cdr->start);
|
get_date(start, sizeof(start), cdr->start);
|
||||||
get_date(answer, cdr->answer);
|
get_date(answer, sizeof(answer), cdr->answer);
|
||||||
get_date(end, cdr->end);
|
get_date(end, sizeof(end), cdr->end);
|
||||||
|
|
||||||
sprintf(
|
ast_mutex_lock(&tds_lock);
|
||||||
sqlcmd,
|
|
||||||
|
/* Ensure that we are connected */
|
||||||
|
if (!settings->connected) {
|
||||||
|
if (mssql_connect()) {
|
||||||
|
/* Connect failed */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
erc = dbfcmd(settings->dbproc,
|
||||||
"INSERT INTO %s "
|
"INSERT INTO %s "
|
||||||
"("
|
"("
|
||||||
"accountcode, "
|
"accountcode, "
|
||||||
@@ -172,7 +176,7 @@ static int tds_log(struct ast_cdr *cdr)
|
|||||||
"'%s', " /* amaflags */
|
"'%s', " /* amaflags */
|
||||||
"'%s'" /* uniqueid */
|
"'%s'" /* uniqueid */
|
||||||
")",
|
")",
|
||||||
table,
|
settings->table,
|
||||||
accountcode,
|
accountcode,
|
||||||
src,
|
src,
|
||||||
dst,
|
dst,
|
||||||
@@ -192,27 +196,26 @@ static int tds_log(struct ast_cdr *cdr)
|
|||||||
uniqueid
|
uniqueid
|
||||||
);
|
);
|
||||||
|
|
||||||
do {
|
if (erc == FAIL) {
|
||||||
if (!connected) {
|
ast_log(LOG_ERROR, "Failed to build INSERT statement, no CDR was logged.\n");
|
||||||
if (mssql_connect())
|
goto done;
|
||||||
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 (dbsqlexec(settings->dbproc) == FAIL) {
|
||||||
if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
|
ast_log(LOG_ERROR, "Failed to execute INSERT statement, no CDR was logged.\n");
|
||||||
#else
|
goto done;
|
||||||
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);
|
|
||||||
|
/* Consume any results we might get back (this is more of a sanity check than
|
||||||
|
* anything else, since an INSERT shouldn't return results). */
|
||||||
|
while (dbresults(settings->dbproc) != NO_MORE_RESULTS) {
|
||||||
|
while (dbnextrow(settings->dbproc) != NO_MORE_ROWS);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
ast_mutex_unlock(&tds_lock);
|
||||||
|
|
||||||
ast_free(accountcode);
|
ast_free(accountcode);
|
||||||
ast_free(src);
|
ast_free(src);
|
||||||
@@ -225,285 +228,252 @@ static int tds_log(struct ast_cdr *cdr)
|
|||||||
ast_free(lastdata);
|
ast_free(lastdata);
|
||||||
ast_free(uniqueid);
|
ast_free(uniqueid);
|
||||||
|
|
||||||
ast_mutex_unlock(&tds_lock);
|
return 0;
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *anti_injection(const char *str, int len)
|
static char *anti_injection(const char *str, int len)
|
||||||
{
|
{
|
||||||
/* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */
|
/* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */
|
||||||
|
|
||||||
char *buf;
|
char *buf;
|
||||||
char *buf_ptr, *srh_ptr;
|
char *buf_ptr, *srh_ptr;
|
||||||
char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"};
|
char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"};
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
if ((buf = ast_malloc(len + 1)) == NULL)
|
if (!(buf = ast_calloc(1, len + 1))) {
|
||||||
{
|
ast_log(LOG_ERROR, "Out of memory\n");
|
||||||
ast_log(LOG_ERROR, "cdr_tds: Out of memory error\n");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(buf, 0, len);
|
|
||||||
|
|
||||||
buf_ptr = buf;
|
buf_ptr = buf;
|
||||||
|
|
||||||
/* Escape single quotes */
|
/* Escape single quotes */
|
||||||
for (; *str && strlen(buf) < len; str++)
|
for (; *str && strlen(buf) < len; str++) {
|
||||||
{
|
if (*str == '\'') {
|
||||||
if (*str == '\'')
|
|
||||||
*buf_ptr++ = '\'';
|
*buf_ptr++ = '\'';
|
||||||
|
}
|
||||||
*buf_ptr++ = *str;
|
*buf_ptr++ = *str;
|
||||||
}
|
}
|
||||||
*buf_ptr = '\0';
|
*buf_ptr = '\0';
|
||||||
|
|
||||||
/* Erase known bad input */
|
/* Erase known bad input */
|
||||||
for (idx=0; *known_bad[idx]; idx++)
|
for (idx = 0; *known_bad[idx]; idx++) {
|
||||||
{
|
while ((srh_ptr = strcasestr(buf, known_bad[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);
|
||||||
{
|
|
||||||
memmove(srh_ptr, srh_ptr+strlen(known_bad[idx]), strlen(srh_ptr+strlen(known_bad[idx]))+1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_date(char *dateField, struct timeval tv)
|
static void get_date(char *dateField, size_t len, struct timeval tv)
|
||||||
{
|
{
|
||||||
struct ast_tm tm;
|
|
||||||
char buf[80];
|
|
||||||
|
|
||||||
/* To make sure we have date variable if not insert null to SQL */
|
/* To make sure we have date variable if not insert null to SQL */
|
||||||
if (!ast_tvzero(tv))
|
if (!ast_tvzero(tv)) {
|
||||||
{
|
struct ast_tm tm;
|
||||||
ast_localtime(&tv, &tm, NULL);
|
ast_localtime(&tv, &tm, NULL);
|
||||||
ast_strftime(buf, 80, DATE_FORMAT, &tm);
|
ast_strftime(dateField, len, "'" DATE_FORMAT "'", &tm);
|
||||||
sprintf(dateField, "'%s'", buf);
|
} else {
|
||||||
}
|
ast_copy_string(dateField, "null", len);
|
||||||
else
|
|
||||||
{
|
|
||||||
strcpy(dateField, "null");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mssql_disconnect(void)
|
static int mssql_disconnect(void)
|
||||||
{
|
{
|
||||||
if (tds) {
|
if (settings->dbproc) {
|
||||||
tds_free_socket(tds);
|
dbclose(settings->dbproc);
|
||||||
tds = NULL;
|
settings->dbproc = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context) {
|
settings->connected = 0;
|
||||||
tds_free_context(context);
|
|
||||||
context = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (login) {
|
|
||||||
tds_free_login(login);
|
|
||||||
login = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
connected = 0;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mssql_connect(void)
|
static int mssql_connect(void)
|
||||||
{
|
{
|
||||||
#if (defined(FREETDS_0_63) || defined(FREETDS_0_64))
|
LOGINREC *login;
|
||||||
TDSCONNECTION *connection = NULL;
|
|
||||||
#else
|
|
||||||
TDSCONNECTINFO *connection = NULL;
|
|
||||||
#endif
|
|
||||||
char query[128];
|
|
||||||
|
|
||||||
/* Connect to M$SQL Server */
|
if ((login = dblogin()) == NULL) {
|
||||||
if (!(login = tds_alloc_login()))
|
ast_log(LOG_ERROR, "Unable to allocate login structure for db-lib\n");
|
||||||
{
|
|
||||||
ast_log(LOG_ERROR, "tds_alloc_login() failed.\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tds_set_server(login, hostname);
|
DBSETLAPP(login, "TSQL");
|
||||||
tds_set_user(login, dbuser);
|
DBSETLUSER(login, (char *) settings->username);
|
||||||
tds_set_passwd(login, password);
|
DBSETLPWD(login, (char *) settings->password);
|
||||||
tds_set_app(login, "TSQL");
|
DBSETLCHARSET(login, (char *) settings->charset);
|
||||||
tds_set_library(login, "TDS-Library");
|
DBSETLNATLANG(login, (char *) settings->language);
|
||||||
#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 ((settings->dbproc = dbopen(login, (char *) settings->hostname)) == NULL) {
|
||||||
if (!(context = tds_alloc_context(NULL)))
|
ast_log(LOG_ERROR, "Unable to connect to %s\n", settings->hostname);
|
||||||
#else
|
dbloginfree(login);
|
||||||
if (!(context = tds_alloc_context()))
|
return -1;
|
||||||
#endif
|
|
||||||
{
|
|
||||||
ast_log(LOG_ERROR, "tds_alloc_context() failed.\n");
|
|
||||||
goto connect_fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(tds = tds_alloc_socket(context, 512))) {
|
dbloginfree(login);
|
||||||
ast_log(LOG_ERROR, "tds_alloc_socket() failed.\n");
|
|
||||||
goto connect_fail;
|
if (dbuse(settings->dbproc, (char *) settings->database) == FAIL) {
|
||||||
|
ast_log(LOG_ERROR, "Unable to select database %s\n", settings->database);
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
tds_set_parent(tds, NULL);
|
if (dbfcmd(settings->dbproc, "SELECT 1 FROM [%s]", settings->table) == FAIL) {
|
||||||
connection = tds_read_config_info(tds, login, context->locale);
|
ast_log(LOG_ERROR, "Unable to build query while verifying the existence of table '%s'\n", settings->table);
|
||||||
if (!connection)
|
goto failed;
|
||||||
{
|
|
||||||
ast_log(LOG_ERROR, "tds_read_config() failed.\n");
|
|
||||||
goto connect_fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tds_connect(tds, connection) == TDS_FAIL)
|
if (dbsqlexec(settings->dbproc) == FAIL) {
|
||||||
{
|
ast_log(LOG_ERROR, "Unable to verify existence of table '%s'\n", settings->table);
|
||||||
ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n");
|
goto failed;
|
||||||
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;
|
|
||||||
|
|
||||||
sprintf(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connected = 1;
|
/* Consume the result set (we don't really care about the result, though) */
|
||||||
|
while (dbresults(settings->dbproc) != NO_MORE_RESULTS) {
|
||||||
|
while (dbnextrow(settings->dbproc) != NO_MORE_ROWS);
|
||||||
|
}
|
||||||
|
|
||||||
|
settings->connected = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
connect_fail:
|
failed:
|
||||||
mssql_disconnect();
|
dbclose(settings->dbproc);
|
||||||
|
settings->dbproc = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tds_unload_module(void)
|
static int tds_unload_module(void)
|
||||||
{
|
{
|
||||||
|
if (settings) {
|
||||||
|
ast_mutex_lock(&tds_lock);
|
||||||
mssql_disconnect();
|
mssql_disconnect();
|
||||||
|
ast_mutex_unlock(&tds_lock);
|
||||||
|
|
||||||
|
ast_string_field_free_memory(settings);
|
||||||
|
ast_free(settings);
|
||||||
|
}
|
||||||
|
|
||||||
ast_cdr_unregister(name);
|
ast_cdr_unregister(name);
|
||||||
|
|
||||||
if (hostname) ast_free(hostname);
|
dbexit();
|
||||||
if (dbname) ast_free(dbname);
|
|
||||||
if (dbuser) ast_free(dbuser);
|
return 0;
|
||||||
if (password) ast_free(password);
|
}
|
||||||
if (charset) ast_free(charset);
|
|
||||||
if (language) ast_free(language);
|
static int tds_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
|
||||||
if (table) ast_free(table);
|
{
|
||||||
|
ast_log(LOG_ERROR, "%s (%d)\n", dberrstr, dberr);
|
||||||
|
|
||||||
|
if (oserr != DBNOERR) {
|
||||||
|
ast_log(LOG_ERROR, "%s (%d)\n", oserrstr, oserr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return INT_CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tds_message_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
|
||||||
|
{
|
||||||
|
ast_debug(1, "Msg %d, Level %d, State %d, Line %d\n", msgno, severity, msgstate, line);
|
||||||
|
ast_log(LOG_NOTICE, "%s\n", msgtext);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tds_load_module(int reload)
|
static int tds_load_module(int reload)
|
||||||
{
|
{
|
||||||
int res = 0;
|
|
||||||
struct ast_config *cfg;
|
struct ast_config *cfg;
|
||||||
struct ast_variable *var;
|
|
||||||
const char *ptr = NULL;
|
const char *ptr = NULL;
|
||||||
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
|
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
|
||||||
#ifdef FREETDS_PRE_0_62
|
|
||||||
TDS_INT result_type;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cfg = ast_config_load(config, config_flags);
|
cfg = ast_config_load(config, config_flags);
|
||||||
if (!cfg) {
|
if (!cfg) {
|
||||||
ast_log(LOG_NOTICE, "Unable to load config for MSSQL CDR's: %s\n", config);
|
ast_log(LOG_NOTICE, "Unable to load TDS config for CDRs: %s\n", config);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
|
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var = ast_variable_browse(cfg, "global");
|
if (!ast_variable_browse(cfg, "global")) {
|
||||||
if (!var) /* nothing configured */ {
|
/* nothing configured */
|
||||||
ast_config_destroy(cfg);
|
ast_config_destroy(cfg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast_mutex_lock(&tds_lock);
|
||||||
|
|
||||||
|
/* Clear out any existing settings */
|
||||||
|
ast_string_field_init(settings, 0);
|
||||||
|
|
||||||
ptr = ast_variable_retrieve(cfg, "global", "hostname");
|
ptr = ast_variable_retrieve(cfg, "global", "hostname");
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
if (hostname)
|
ast_string_field_set(settings, hostname, ptr);
|
||||||
ast_free(hostname);
|
} else {
|
||||||
hostname = ast_strdup(ptr);
|
ast_log(LOG_ERROR, "Failed to connect: Database server hostname not specified.\n");
|
||||||
} else
|
goto failed;
|
||||||
ast_log(LOG_ERROR, "Database server hostname not specified.\n");
|
}
|
||||||
|
|
||||||
ptr = ast_variable_retrieve(cfg, "global", "dbname");
|
ptr = ast_variable_retrieve(cfg, "global", "dbname");
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
if (dbname)
|
ast_string_field_set(settings, database, ptr);
|
||||||
ast_free(dbname);
|
} else {
|
||||||
dbname = ast_strdup(ptr);
|
ast_log(LOG_ERROR, "Failed to connect: Database dbname not specified.\n");
|
||||||
} else
|
goto failed;
|
||||||
ast_log(LOG_ERROR, "Database dbname not specified.\n");
|
}
|
||||||
|
|
||||||
ptr = ast_variable_retrieve(cfg, "global", "user");
|
ptr = ast_variable_retrieve(cfg, "global", "user");
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
if (dbuser)
|
ast_string_field_set(settings, username, ptr);
|
||||||
ast_free(dbuser);
|
} else {
|
||||||
dbuser = ast_strdup(ptr);
|
ast_log(LOG_ERROR, "Failed to connect: Database dbuser not specified.\n");
|
||||||
} else
|
goto failed;
|
||||||
ast_log(LOG_ERROR, "Database dbuser not specified.\n");
|
}
|
||||||
|
|
||||||
ptr = ast_variable_retrieve(cfg, "global", "password");
|
ptr = ast_variable_retrieve(cfg, "global", "password");
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
if (password)
|
ast_string_field_set(settings, password, ptr);
|
||||||
ast_free(password);
|
} else {
|
||||||
password = ast_strdup(ptr);
|
ast_log(LOG_ERROR, "Failed to connect: Database password not specified.\n");
|
||||||
} else
|
goto failed;
|
||||||
ast_log(LOG_ERROR,"Database password not specified.\n");
|
}
|
||||||
|
|
||||||
ptr = ast_variable_retrieve(cfg, "global", "charset");
|
ptr = ast_variable_retrieve(cfg, "global", "charset");
|
||||||
if (charset)
|
if (ptr) {
|
||||||
ast_free(charset);
|
ast_string_field_set(settings, charset, ptr);
|
||||||
if (ptr)
|
} else {
|
||||||
charset = ast_strdup(ptr);
|
ast_string_field_set(settings, charset, "iso_1");
|
||||||
else
|
}
|
||||||
charset = ast_strdup("iso_1");
|
|
||||||
|
|
||||||
if (language)
|
|
||||||
ast_free(language);
|
|
||||||
ptr = ast_variable_retrieve(cfg, "global", "language");
|
ptr = ast_variable_retrieve(cfg, "global", "language");
|
||||||
if (ptr)
|
if (ptr) {
|
||||||
language = ast_strdup(ptr);
|
ast_string_field_set(settings, language, ptr);
|
||||||
else
|
} else {
|
||||||
language = ast_strdup("us_english");
|
ast_string_field_set(settings, language, "us_english");
|
||||||
|
}
|
||||||
|
|
||||||
ptr = ast_variable_retrieve(cfg, "global", "table");
|
ptr = ast_variable_retrieve(cfg, "global", "table");
|
||||||
if (ptr == NULL) {
|
if (ptr) {
|
||||||
ast_debug(1, "cdr_tds: table not specified. Assuming cdr\n");
|
ast_string_field_set(settings, table, ptr);
|
||||||
ptr = "cdr";
|
} else {
|
||||||
|
ast_log(LOG_NOTICE, "Table name not specified, using 'cdr' by default.\n");
|
||||||
|
ast_string_field_set(settings, table, "cdr");
|
||||||
}
|
}
|
||||||
if (table)
|
|
||||||
ast_free(table);
|
|
||||||
table = ast_strdup(ptr);
|
|
||||||
|
|
||||||
|
mssql_disconnect();
|
||||||
|
|
||||||
|
if (mssql_connect()) {
|
||||||
|
/* We failed to connect (mssql_connect takes care of logging it) */
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_mutex_unlock(&tds_lock);
|
||||||
ast_config_destroy(cfg);
|
ast_config_destroy(cfg);
|
||||||
|
|
||||||
ast_mutex_lock(&tds_lock);
|
return 1;
|
||||||
mssql_disconnect();
|
|
||||||
mssql_connect();
|
|
||||||
ast_mutex_unlock(&tds_lock);
|
|
||||||
|
|
||||||
return res;
|
failed:
|
||||||
|
ast_mutex_unlock(&tds_lock);
|
||||||
|
ast_config_destroy(cfg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reload(void)
|
static int reload(void)
|
||||||
@@ -513,9 +483,35 @@ static int reload(void)
|
|||||||
|
|
||||||
static int load_module(void)
|
static int load_module(void)
|
||||||
{
|
{
|
||||||
if (!tds_load_module(0))
|
if (dbinit() == FAIL) {
|
||||||
|
ast_log(LOG_ERROR, "Failed to initialize FreeTDS db-lib\n");
|
||||||
return AST_MODULE_LOAD_DECLINE;
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dberrhandle(tds_error_handler);
|
||||||
|
dbmsghandle(tds_message_handler);
|
||||||
|
|
||||||
|
settings = ast_calloc(1, sizeof(*settings));
|
||||||
|
|
||||||
|
if (!settings || ast_string_field_init(settings, 256)) {
|
||||||
|
if (settings) {
|
||||||
|
ast_free(settings);
|
||||||
|
settings = NULL;
|
||||||
|
}
|
||||||
|
dbexit();
|
||||||
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tds_load_module(0)) {
|
||||||
|
ast_string_field_free_memory(settings);
|
||||||
|
ast_free(settings);
|
||||||
|
settings = NULL;
|
||||||
|
dbexit();
|
||||||
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
|
||||||
ast_cdr_register(name, ast_module_info->description, tds_log);
|
ast_cdr_register(name, ast_module_info->description, tds_log);
|
||||||
|
|
||||||
return AST_MODULE_LOAD_SUCCESS;
|
return AST_MODULE_LOAD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,7 +520,7 @@ static int unload_module(void)
|
|||||||
return tds_unload_module();
|
return tds_unload_module();
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MSSQL CDR Backend",
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "FreeTDS CDR Backend",
|
||||||
.load = load_module,
|
.load = load_module,
|
||||||
.unload = unload_module,
|
.unload = unload_module,
|
||||||
.reload = reload,
|
.reload = reload,
|
||||||
|
|||||||
29
configure.ac
29
configure.ac
@@ -1380,34 +1380,7 @@ fi
|
|||||||
|
|
||||||
AST_EXT_TOOL_CHECK([GMIME], [gmime])
|
AST_EXT_TOOL_CHECK([GMIME], [gmime])
|
||||||
|
|
||||||
AST_EXT_LIB_CHECK([FREETDS], [tds], [tds_version], [tds.h])
|
AST_EXT_LIB_CHECK([FREETDS], [sybdb], [dbinit], [sybdb.h])
|
||||||
if test "${PBX_FREETDS}" != "0";
|
|
||||||
then
|
|
||||||
if test "${FREETDS_DIR}x" = "x";
|
|
||||||
then
|
|
||||||
for tds_dir in /usr /usr/local;
|
|
||||||
do
|
|
||||||
if test -f "${tds_dir}/include/tdsver.h";
|
|
||||||
then
|
|
||||||
FREETDS_DIR="${tds_dir}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
case `${GREP} TDS_VERSION_NO ${FREETDS_DIR:-/usr}/include/tdsver.h` in
|
|
||||||
*0.64*)
|
|
||||||
FREETDS_INCLUDE="${FREETDS_INCLUDE} -DFREETDS_0_64"
|
|
||||||
;;
|
|
||||||
*0.63*)
|
|
||||||
FREETDS_INCLUDE="${FREETDS_INCLUDE} -DFREETDS_0_63"
|
|
||||||
;;
|
|
||||||
*0.62*)
|
|
||||||
FREETDS_INCLUDE="${FREETDS_INCLUDE} -DFREETDS_0_62"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
FREETDS_INCLUDE="${FREETDS_INCLUDE} -DFREETDS_PRE_0_62"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
AST_EXT_LIB_CHECK([TERMCAP], [termcap], [tgetent], [])
|
AST_EXT_LIB_CHECK([TERMCAP], [termcap], [tgetent], [])
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,6 @@
|
|||||||
The cdr\_tds module is NOT compatible with version 0.63 of FreeTDS.
|
The cdr\_tds module now works with most modern release versions of FreeTDS (from
|
||||||
|
at least 0.60 through 0.82). Although versions of FreeTDS prior to 0.82 will
|
||||||
The cdr\_tds module is known to work with FreeTDS version 0.62.1;
|
work, we recommend using the latest available version for performance and
|
||||||
it should also work with 0.62.2, 0.62.3 and 0.62.4, which are bug
|
stability reasons.
|
||||||
fix releases.
|
|
||||||
|
|
||||||
The cdr\_tds module uses the raw "libtds" API of FreeTDS. It appears
|
|
||||||
that from 0.63 onwards, this is not considered a published API
|
|
||||||
of FreeTDS and is subject to change without notice.
|
|
||||||
|
|
||||||
Between 0.62.x and 0.63 of FreeTDS, many incompatible changes
|
|
||||||
have been made to the libtds API.
|
|
||||||
|
|
||||||
For newer versions of FreeTDS, it is recommended that you use the
|
|
||||||
ODBC driver.
|
|
||||||
|
|
||||||
|
The latest release of FreeTDS is available from http://www.freetds.org/
|
||||||
|
|||||||
@@ -1157,9 +1157,6 @@
|
|||||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||||
# undef _POSIX_PTHREAD_SEMANTICS
|
# undef _POSIX_PTHREAD_SEMANTICS
|
||||||
#endif
|
#endif
|
||||||
#ifndef _TANDEM_SOURCE
|
|
||||||
# undef _TANDEM_SOURCE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Define like PROTOTYPES; this can be used by system headers. */
|
/* Define like PROTOTYPES; this can be used by system headers. */
|
||||||
#undef __PROTOTYPES
|
#undef __PROTOTYPES
|
||||||
|
|||||||
Reference in New Issue
Block a user