Sat Nov 25 00:45:50 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 <tds.h>
#include <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, and malloc.

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 523 of file cdr_tds.c.

References ASTERISK_GPL_KEY.

00524 {
00525    return ASTERISK_GPL_KEY;
00526 }

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 502 of file cdr_tds.c.

References tds_load_module().

00503 {
00504    return tds_load_module();
00505 }

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 }

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 496 of file cdr_tds.c.

References tds_load_module(), and tds_unload_module().

00497 {
00498    tds_unload_module();
00499    return tds_load_module();
00500 }

static int tds_load_module void   )  [static]
 

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

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

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 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 
00423    return 0;
00424 }

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 507 of file cdr_tds.c.

References tds_unload_module().

00508 {
00509    return tds_unload_module();
00510 }

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 512 of file cdr_tds.c.

References ast_mutex_trylock(), and ast_mutex_unlock().

00513 {
00514    /* Simplistic use count */
00515    if (ast_mutex_trylock(&tds_lock)) {
00516       return 1;
00517    } else {
00518       ast_mutex_unlock(&tds_lock);
00519       return 0;
00520    }
00521 }


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 Sat Nov 25 00:45:50 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6