Mon Jul 14 17:25:09 2008

Asterisk developer's documentation


cdr_tds.c File Reference

FreeTDS CDR logger. More...

#include "asterisk.h"
#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"

Include dependency graph for cdr_tds.c:

Go to the source code of this file.

Defines

#define DATE_FORMAT   "%Y/%m/%d %T"

Functions

static char * anti_injection (const char *, int)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"MSSQL CDR Backend",.load=load_module,.unload=unload_module,.reload=reload,)
 AST_MUTEX_DEFINE_STATIC (tds_lock)
static void get_date (char *, struct timeval)
static int load_module (void)
static int mssql_connect (void)
static int mssql_disconnect (void)
static int reload (void)
static int tds_load_module (void)
static int tds_log (struct ast_cdr *cdr)
static int tds_unload_module (void)
static int unload_module (void)

Variables

static char * charset = NULL
static char * config = "cdr_tds.conf"
static int connected = 0
static TDSCONTEXT * context
static char * dbname = NULL
static char * dbuser = NULL
static char * hostname = NULL
static char * language = NULL
static TDSLOGIN * login
static char * name = "mssql"
static char * password = NULL
static char * table = NULL
static TDSSOCKET * tds


Detailed Description

FreeTDS CDR logger.

See also

Definition in file cdr_tds.c.


Define Documentation

#define DATE_FORMAT   "%Y/%m/%d %T"

 *
 * 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
) ON [PRIMARY]

Definition at line 89 of file cdr_tds.c.


Function Documentation

static char * anti_injection ( const char *  ,
int   
) [static]

Definition at line 240 of file cdr_tds.c.

References ast_log(), LOG_ERROR, malloc, and strcasestr().

Referenced by tds_log().

00241 {
00242    /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */
00243 
00244    char *buf;
00245    char *buf_ptr, *srh_ptr;
00246    char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"};
00247    int idx;
00248 
00249    if ((buf = malloc(len + 1)) == NULL)
00250    {
00251       ast_log(LOG_ERROR, "cdr_tds:  Out of memory error\n");
00252       return NULL;
00253    }
00254    memset(buf, 0, len);
00255 
00256    buf_ptr = buf;
00257 
00258    /* Escape single quotes */
00259    for (; *str && strlen(buf) < len; str++)
00260    {
00261       if (*str == '\'')
00262          *buf_ptr++ = '\'';
00263       *buf_ptr++ = *str;
00264    }
00265    *buf_ptr = '\0';
00266 
00267    /* Erase known bad input */
00268    for (idx=0; *known_bad[idx]; idx++)
00269    {
00270       while((srh_ptr = strcasestr(buf, known_bad[idx])))
00271       {
00272          memmove(srh_ptr, srh_ptr+strlen(known_bad[idx]), strlen(srh_ptr+strlen(known_bad[idx]))+1);
00273       }
00274    }
00275 
00276    return buf;
00277 }

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"MSSQL CDR Backend"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

AST_MUTEX_DEFINE_STATIC ( tds_lock   ) 

static void get_date ( char *  ,
struct  timeval 
) [static]

Definition at line 279 of file cdr_tds.c.

References ast_localtime(), DATE_FORMAT, and t.

00280 {
00281    struct tm tm;
00282    time_t t;
00283    char buf[80];
00284 
00285    /* To make sure we have date variable if not insert null to SQL */
00286    if (!ast_tvzero(tv))
00287    {
00288       t = tv.tv_sec;
00289       ast_localtime(&t, &tm, NULL);
00290       strftime(buf, 80, DATE_FORMAT, &tm);
00291       sprintf(dateField, "'%s'", buf);
00292    }
00293    else
00294    {
00295       strcpy(dateField, "null");
00296    }
00297 }

static int load_module ( void   )  [static]

Definition at line 512 of file cdr_tds.c.

References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and tds_load_module().

00513 {
00514    if(!tds_load_module())
00515       return AST_MODULE_LOAD_DECLINE;
00516    else 
00517       return AST_MODULE_LOAD_SUCCESS;
00518 }

static int mssql_connect ( void   )  [static]

Definition at line 321 of file cdr_tds.c.

References ast_log(), LOG_ERROR, and mssql_disconnect().

Referenced by tds_load_module(), and tds_log().

00322 {
00323 #if (defined(FREETDS_0_63) || defined(FREETDS_0_64))
00324    TDSCONNECTION *connection = NULL;
00325 #else
00326    TDSCONNECTINFO *connection = NULL;
00327 #endif
00328    char query[128];
00329 
00330    /* Connect to M$SQL Server */
00331    if (!(login = tds_alloc_login()))
00332    {
00333       ast_log(LOG_ERROR, "tds_alloc_login() failed.\n");
00334       return -1;
00335    }
00336    
00337    tds_set_server(login, hostname);
00338    tds_set_user(login, dbuser);
00339    tds_set_passwd(login, password);
00340    tds_set_app(login, "TSQL");
00341    tds_set_library(login, "TDS-Library");
00342 #ifndef FREETDS_PRE_0_62
00343    tds_set_client_charset(login, charset);
00344 #endif
00345    tds_set_language(login, language);
00346    tds_set_packet(login, 512);
00347    tds_set_version(login, 7, 0);
00348 
00349 #ifdef FREETDS_0_64
00350    if (!(context = tds_alloc_context(NULL)))
00351 #else
00352    if (!(context = tds_alloc_context()))
00353 #endif
00354    {
00355       ast_log(LOG_ERROR, "tds_alloc_context() failed.\n");
00356       goto connect_fail;
00357    }
00358 
00359    if (!(tds = tds_alloc_socket(context, 512))) {
00360       ast_log(LOG_ERROR, "tds_alloc_socket() failed.\n");
00361       goto connect_fail;
00362    }
00363 
00364    tds_set_parent(tds, NULL);
00365    connection = tds_read_config_info(tds, login, context->locale);
00366    if (!connection)
00367    {
00368       ast_log(LOG_ERROR, "tds_read_config() failed.\n");
00369       goto connect_fail;
00370    }
00371 
00372    if (tds_connect(tds, connection) == TDS_FAIL)
00373    {
00374       ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n");
00375       tds = NULL; /* freed by tds_connect() on error */
00376 #if (defined(FREETDS_0_63) || defined(FREETDS_0_64))
00377       tds_free_connection(connection);
00378 #else
00379       tds_free_connect(connection);
00380 #endif
00381       connection = NULL;
00382       goto connect_fail;
00383    }
00384 #if (defined(FREETDS_0_63) || defined(FREETDS_0_64))
00385    tds_free_connection(connection);
00386 #else
00387    tds_free_connect(connection);
00388 #endif
00389    connection = NULL;
00390 
00391    sprintf(query, "USE %s", dbname);
00392 #ifdef FREETDS_PRE_0_62
00393    if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
00394 #else
00395    if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
00396 #endif
00397    {
00398       ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname);
00399       goto connect_fail;
00400    }
00401 
00402    connected = 1;
00403    return 0;
00404 
00405 connect_fail:
00406    mssql_disconnect();
00407    return -1;
00408 }

static int mssql_disconnect ( void   )  [static]

Definition at line 299 of file cdr_tds.c.

Referenced by mssql_connect(), tds_log(), and tds_unload_module().

00300 {
00301    if (tds) {
00302       tds_free_socket(tds);
00303       tds = NULL;
00304    }
00305 
00306    if (context) {
00307       tds_free_context(context);
00308       context = NULL;
00309    }
00310 
00311    if (login) {
00312       tds_free_login(login);
00313       login = NULL;
00314    }
00315 
00316    connected = 0;
00317 
00318    return 0;
00319 }

static int reload ( void   )  [static]

Definition at line 506 of file cdr_tds.c.

References tds_load_module(), and tds_unload_module().

00507 {
00508    tds_unload_module();
00509    return tds_load_module();
00510 }

static int tds_load_module ( void   )  [static]

Definition at line 427 of file cdr_tds.c.

References ast_cdr_register(), ast_config_destroy(), ast_config_load(), ast_log(), ast_variable_browse(), ast_variable_retrieve(), LOG_DEBUG, LOG_ERROR, LOG_NOTICE, mssql_connect(), strdup, tds_log(), and var.

Referenced by load_module(), and reload().

00428 {
00429    int res = 0;
00430    struct ast_config *cfg;
00431    struct ast_variable *var;
00432    const char *ptr = NULL;
00433 #ifdef FREETDS_PRE_0_62
00434    TDS_INT result_type;
00435 #endif
00436 
00437    cfg = ast_config_load(config);
00438    if (!cfg) {
00439       ast_log(LOG_NOTICE, "Unable to load config for MSSQL CDR's: %s\n", config);
00440       return 0;
00441    }
00442 
00443    var = ast_variable_browse(cfg, "global");
00444    if (!var) /* nothing configured */ {
00445       ast_config_destroy(cfg);
00446       return 0;
00447    }
00448    
00449    ptr = ast_variable_retrieve(cfg, "global", "hostname");
00450    if (ptr)
00451       hostname = strdup(ptr);
00452    else
00453       ast_log(LOG_ERROR,"Database server hostname not specified.\n");
00454 
00455    ptr = ast_variable_retrieve(cfg, "global", "dbname");
00456    if (ptr)
00457       dbname = strdup(ptr);
00458    else
00459       ast_log(LOG_ERROR,"Database dbname not specified.\n");
00460 
00461    ptr = ast_variable_retrieve(cfg, "global", "user");
00462    if (ptr)
00463       dbuser = strdup(ptr);
00464    else
00465       ast_log(LOG_ERROR,"Database dbuser not specified.\n");
00466 
00467    ptr = ast_variable_retrieve(cfg, "global", "password");
00468    if (ptr)
00469       password = strdup(ptr);
00470    else
00471       ast_log(LOG_ERROR,"Database password not specified.\n");
00472 
00473    ptr = ast_variable_retrieve(cfg, "global", "charset");
00474    if (ptr)
00475       charset = strdup(ptr);
00476    else
00477       charset = strdup("iso_1");
00478 
00479    ptr = ast_variable_retrieve(cfg, "global", "language");
00480    if (ptr)
00481       language = strdup(ptr);
00482    else
00483       language = strdup("us_english");
00484 
00485    ptr = ast_variable_retrieve(cfg,"global","table");
00486    if (ptr == NULL) {
00487       ast_log(LOG_DEBUG,"cdr_tds: table not specified.  Assuming cdr\n");
00488       ptr = "cdr";
00489    }
00490    table = strdup(ptr);
00491 
00492    ast_config_destroy(cfg);
00493 
00494    mssql_connect();
00495 
00496    /* Register MSSQL CDR handler */
00497    res = ast_cdr_register(name, ast_module_info->description, tds_log);
00498    if (res)
00499    {
00500       ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n");
00501    }
00502 
00503    return res;
00504 }

static int tds_log ( struct ast_cdr cdr  )  [static]

Definition at line 111 of file cdr_tds.c.

References ast_cdr::accountcode, accountcode, ast_cdr::amaflags, ast_cdr::answer, answer, anti_injection(), ast_cdr_disp2str(), ast_cdr_flags2str(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_cdr::billsec, ast_cdr::channel, ast_cdr::clid, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, free, get_date(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_ERROR, LOG_WARNING, mssql_connect(), mssql_disconnect(), ast_cdr::src, ast_cdr::start, and ast_cdr::uniqueid.

Referenced by tds_load_module().

00112 {
00113    char sqlcmd[2048], start[80], answer[80], end[80];
00114    char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid;
00115    int res = 0;
00116    int retried = 0;
00117 #ifdef FREETDS_PRE_0_62
00118    TDS_INT result_type;
00119 #endif
00120 
00121    ast_mutex_lock(&tds_lock);
00122 
00123    memset(sqlcmd, 0, 2048);
00124 
00125    accountcode = anti_injection(cdr->accountcode, 20);
00126    src = anti_injection(cdr->src, 80);
00127    dst = anti_injection(cdr->dst, 80);
00128    dcontext = anti_injection(cdr->dcontext, 80);
00129    clid = anti_injection(cdr->clid, 80);
00130    channel = anti_injection(cdr->channel, 80);
00131    dstchannel = anti_injection(cdr->dstchannel, 80);
00132    lastapp = anti_injection(cdr->lastapp, 80);
00133    lastdata = anti_injection(cdr->lastdata, 80);
00134    uniqueid = anti_injection(cdr->uniqueid, 32);
00135 
00136    get_date(start, cdr->start);
00137    get_date(answer, cdr->answer);
00138    get_date(end, cdr->end);
00139 
00140    sprintf(
00141       sqlcmd,
00142       "INSERT INTO %s "
00143       "("
00144          "accountcode, "
00145          "src, "
00146          "dst, "
00147          "dcontext, "
00148          "clid, "
00149          "channel, "
00150          "dstchannel, "
00151          "lastapp, "
00152          "lastdata, "
00153          "start, "
00154          "answer, "
00155          "[end], "
00156          "duration, "
00157          "billsec, "
00158          "disposition, "
00159          "amaflags, "
00160          "uniqueid"
00161       ") "
00162       "VALUES "
00163       "("
00164          "'%s', " /* accountcode */
00165          "'%s', " /* src */
00166          "'%s', " /* dst */
00167          "'%s', " /* dcontext */
00168          "'%s', " /* clid */
00169          "'%s', " /* channel */
00170          "'%s', " /* dstchannel */
00171          "'%s', " /* lastapp */
00172          "'%s', " /* lastdata */
00173          "%s, "      /* start */
00174          "%s, "      /* answer */
00175          "%s, "      /* end */
00176          "%ld, "     /* duration */
00177          "%ld, "     /* billsec */
00178          "'%s', " /* disposition */
00179          "'%s', " /* amaflags */
00180          "'%s'"      /* uniqueid */
00181       ")",
00182       table,
00183       accountcode,
00184       src,
00185       dst,
00186       dcontext,
00187       clid,
00188       channel,
00189       dstchannel,
00190       lastapp,
00191       lastdata,
00192       start,
00193       answer,
00194       end,
00195       cdr->duration,
00196       cdr->billsec,
00197       ast_cdr_disp2str(cdr->disposition),
00198       ast_cdr_flags2str(cdr->amaflags),
00199       uniqueid
00200    );
00201 
00202    do {
00203       if (!connected) {
00204          if (mssql_connect())
00205             ast_log(LOG_ERROR, "Failed to reconnect to SQL database.\n");
00206          else
00207             ast_log(LOG_WARNING, "Reconnected to SQL database.\n");
00208 
00209          retried = 1;   /* note that we have now tried */
00210       }
00211 
00212 #ifdef FREETDS_PRE_0_62
00213       if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
00214 #else
00215       if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
00216 #endif
00217       {
00218          ast_log(LOG_ERROR, "Failed to insert Call Data Record into SQL database.\n");
00219 
00220          mssql_disconnect();  /* this is ok even if we are already disconnected */
00221       }
00222    } while (!connected && !retried);
00223 
00224    free(accountcode);
00225    free(src);
00226    free(dst);
00227    free(dcontext);
00228    free(clid);
00229    free(channel);
00230    free(dstchannel);
00231    free(lastapp);
00232    free(lastdata);
00233    free(uniqueid);
00234 
00235    ast_mutex_unlock(&tds_lock);
00236 
00237    return res;
00238 }

static int tds_unload_module ( void   )  [static]

Definition at line 410 of file cdr_tds.c.

References ast_cdr_unregister(), free, and mssql_disconnect().

Referenced by reload(), and unload_module().

00411 {
00412    mssql_disconnect();
00413 
00414    ast_cdr_unregister(name);
00415 
00416    if (hostname) free(hostname);
00417    if (dbname) free(dbname);
00418    if (dbuser) free(dbuser);
00419    if (password) free(password);
00420    if (charset) free(charset);
00421    if (language) free(language);
00422    if (table) free(table);
00423 
00424    return 0;
00425 }

static int unload_module ( void   )  [static]

Definition at line 520 of file cdr_tds.c.

References tds_unload_module().

00521 {
00522    return tds_unload_module();
00523 }


Variable Documentation

char * charset = NULL [static]

Definition at line 94 of file cdr_tds.c.

char* config = "cdr_tds.conf" [static]

Definition at line 92 of file cdr_tds.c.

int connected = 0 [static]

Definition at line 97 of file cdr_tds.c.

TDSCONTEXT* context [static]

Definition at line 103 of file cdr_tds.c.

char * dbname = NULL [static]

Definition at line 94 of file cdr_tds.c.

Referenced by lookupcidname_exec(), parse_config(), pgsql_reconnect(), and realtime_pgsql_status().

char * dbuser = NULL [static]

Definition at line 94 of file cdr_tds.c.

Referenced by parse_config(), pgsql_reconnect(), and realtime_pgsql_status().

char* hostname = NULL [static]

Definition at line 94 of file cdr_tds.c.

char * language = NULL [static]

Definition at line 94 of file cdr_tds.c.

TDSLOGIN* login [static]

Definition at line 102 of file cdr_tds.c.

char* name = "mssql" [static]

Definition at line 91 of file cdr_tds.c.

char * password = NULL [static]

Definition at line 94 of file cdr_tds.c.

char* table = NULL [static]

Definition at line 95 of file cdr_tds.c.

TDSSOCKET* tds [static]

Definition at line 101 of file cdr_tds.c.


Generated on Mon Jul 14 17:25:09 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1