Mon Sep 18 09:14:03 2006

Asterisk developer's documentation


cdr_tds.c File Reference

FreeTDS CDR logger. More...

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <math.h>
#include <freetds_mssql/tds.h>
#include <freetds_mssql/tdsconvert.h>
#include <ctype.h>
#include "asterisk.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"

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_MUTEX_DEFINE_STATIC (tds_lock)
char * description (void)
 Provides a description of the module.
static void get_date (char *, struct timeval)
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
static int mssql_connect (void)
static int mssql_disconnect (void)
int reload (void)
 Reload stuff.
static int tds_load_module (void)
static int tds_log (struct ast_cdr *cdr)
static int tds_unload_module (void)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

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 * desc = "MSSQL CDR Backend"
static char * hostname = NULL
static char * language = NULL
static TDSLOGIN * login
static char * name = "mssql"
static char * password = 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 85 of file cdr_tds.c.


Function Documentation

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

Definition at line 235 of file cdr_tds.c.

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

Referenced by tds_log().

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

AST_MUTEX_DEFINE_STATIC ( tds_lock   ) 

char* description ( void   ) 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 294 of file cdr_tds.c.

00295 {
00296    return desc;
00297 }

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

Definition at line 274 of file cdr_tds.c.

References DATE_FORMAT, and t.

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

char* key ( void   ) 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 519 of file cdr_tds.c.

References ASTERISK_GPL_KEY.

00520 {
00521    return ASTERISK_GPL_KEY;
00522 }

int load_module ( void   ) 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 498 of file cdr_tds.c.

References tds_load_module().

00499 {
00500    return tds_load_module();
00501 }

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 #ifdef FREETDS_0_63
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    if (!(context = tds_alloc_context(NULL)))
00350    {
00351       ast_log(LOG_ERROR, "tds_alloc_context() failed.\n");
00352       goto connect_fail;
00353    }
00354 
00355    if (!(tds = tds_alloc_socket(context, 512))) {
00356       ast_log(LOG_ERROR, "tds_alloc_socket() failed.\n");
00357       goto connect_fail;
00358    }
00359 
00360    tds_set_parent(tds, NULL);
00361    connection = tds_read_config_info(tds, login, context->locale);
00362    if (!connection)
00363    {
00364       ast_log(LOG_ERROR, "tds_read_config() failed.\n");
00365       goto connect_fail;
00366    }
00367 
00368    if (tds_connect(tds, connection) == TDS_FAIL)
00369    {
00370       ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n");
00371       tds = NULL; /* freed by tds_connect() on error */
00372 #ifdef FREETDS_0_63
00373       tds_free_connection(connection);
00374 #else
00375       tds_free_connect(connection);
00376 #endif
00377       connection = NULL;
00378       goto connect_fail;
00379    }
00380 #ifdef FREETDS_0_63
00381    tds_free_connection(connection);
00382 #else
00383    tds_free_connect(connection);
00384 #endif
00385    connection = NULL;
00386 
00387    sprintf(query, "USE %s", dbname);
00388 #ifdef FREETDS_PRE_0_62
00389    if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
00390 #else
00391    if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
00392 #endif
00393    {
00394       ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname);
00395       goto connect_fail;
00396    }
00397 
00398    connected = 1;
00399    return 0;
00400 
00401 connect_fail:
00402    mssql_disconnect();
00403    return -1;
00404 }

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 }

int reload ( void   ) 

Reload stuff.

This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.

Returns:
The return value is not used.

Definition at line 492 of file cdr_tds.c.

References tds_load_module(), and tds_unload_module().

00493 {
00494    tds_unload_module();
00495    return tds_load_module();
00496 }

static int tds_load_module ( void   )  [static]

Definition at line 422 of file cdr_tds.c.

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

Referenced by load_module(), and reload().

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

static int tds_log ( struct ast_cdr cdr  )  [static]

Definition at line 107 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().

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

static int tds_unload_module ( void   )  [static]

Definition at line 406 of file cdr_tds.c.

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

Referenced by reload(), and unload_module().

00407 {
00408    mssql_disconnect();
00409 
00410    ast_cdr_unregister(name);
00411 
00412    if (hostname) free(hostname);
00413    if (dbname) free(dbname);
00414    if (dbuser) free(dbuser);
00415    if (password) free(password);
00416    if (charset) free(charset);
00417    if (language) free(language);
00418 
00419    return 0;
00420 }

int unload_module ( void   ) 

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
Zero on success, or non-zero on error.

Definition at line 503 of file cdr_tds.c.

References tds_unload_module().

00504 {
00505    return tds_unload_module();
00506 }

int usecount ( void   ) 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 508 of file cdr_tds.c.

References ast_mutex_trylock(), and ast_mutex_unlock().

00509 {
00510    /* Simplistic use count */
00511    if (ast_mutex_trylock(&tds_lock)) {
00512       return 1;
00513    } else {
00514       ast_mutex_unlock(&tds_lock);
00515       return 0;
00516    }
00517 }


Variable Documentation

char * charset = NULL [static]

Definition at line 91 of file cdr_tds.c.

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

Definition at line 89 of file cdr_tds.c.

int connected = 0 [static]

Definition at line 93 of file cdr_tds.c.

TDSCONTEXT* context [static]

Definition at line 99 of file cdr_tds.c.

char * dbname = NULL [static]

Definition at line 91 of file cdr_tds.c.

Referenced by lookupcidname_exec().

char * dbuser = NULL [static]

Definition at line 91 of file cdr_tds.c.

char* desc = "MSSQL CDR Backend" [static]

Definition at line 87 of file cdr_tds.c.

char* hostname = NULL [static]

Definition at line 91 of file cdr_tds.c.

char * language = NULL [static]

Definition at line 91 of file cdr_tds.c.

TDSLOGIN* login [static]

Definition at line 98 of file cdr_tds.c.

char* name = "mssql" [static]

Definition at line 88 of file cdr_tds.c.

char * password = NULL [static]

Definition at line 91 of file cdr_tds.c.

TDSSOCKET* tds [static]

Definition at line 97 of file cdr_tds.c.


Generated on Mon Sep 18 09:14:03 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7