Wed Oct 28 13:31:56 2009

Asterisk developer's documentation


cdr_tds.c File Reference

FreeTDS CDR logger. More...

#include "asterisk.h"
#include <time.h>
#include <math.h>
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include <sqlfront.h>
#include <sybdb.h>

Include dependency graph for cdr_tds.c:

Go to the source code of this file.

Data Structures

struct  cdr_tds_config

Defines

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static char * anti_injection (const char *, int)
static int execute_and_consume (DBPROCESS *dbproc, const char *fmt,...)
static void get_date (char *, size_t len, struct timeval)
static int load_module (void)
static int mssql_connect (void)
static int mssql_disconnect (void)
static int reload (void)
static int tds_error_handler (DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
static int tds_load_module (int reload)
static int tds_log (struct ast_cdr *cdr)
static int tds_message_handler (DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
static int tds_unload_module (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "FreeTDS CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_module_infoast_module_info = &__mod_info
static char * config = "cdr_tds.conf"
static char * name = "FreeTDS (MSSQL)"
static struct cdr_tds_configsettings
static ast_mutex_t tds_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )


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 ,
	[userfield] [varchar] (256) NULL
) ON [PRIMARY]

Definition at line 78 of file cdr_tds.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 574 of file cdr_tds.c.

static void __unreg_module ( void   )  [static]

Definition at line 574 of file cdr_tds.c.

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

Definition at line 245 of file cdr_tds.c.

References ast_calloc, ast_log(), buf, LOG_ERROR, and strcasestr().

Referenced by tds_log().

00246 {
00247    /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */
00248    char *buf;
00249    char *buf_ptr, *srh_ptr;
00250    char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"};
00251    int idx;
00252 
00253    if (!(buf = ast_calloc(1, len + 1))) {
00254       ast_log(LOG_ERROR, "Out of memory\n");
00255       return NULL;
00256    }
00257 
00258    buf_ptr = buf;
00259 
00260    /* Escape single quotes */
00261    for (; *str && strlen(buf) < len; str++) {
00262       if (*str == '\'') {
00263          *buf_ptr++ = '\'';
00264       }
00265       *buf_ptr++ = *str;
00266    }
00267    *buf_ptr = '\0';
00268 
00269    /* Erase known bad input */
00270    for (idx = 0; *known_bad[idx]; idx++) {
00271       while ((srh_ptr = strcasestr(buf, known_bad[idx]))) {
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 }

static int execute_and_consume ( DBPROCESS *  dbproc,
const char *  fmt,
  ... 
) [static]

Definition at line 291 of file cdr_tds.c.

References ast_vasprintf, and free.

Referenced by mssql_connect().

00292 {
00293    va_list ap;
00294    char *buffer;
00295 
00296    va_start(ap, fmt);
00297    if (ast_vasprintf(&buffer, fmt, ap) < 0) {
00298       va_end(ap);
00299       return 1;
00300    }
00301    va_end(ap);
00302 
00303    if (dbfcmd(dbproc, buffer) == FAIL) {
00304       free(buffer);
00305       return 1;
00306    }
00307 
00308    free(buffer);
00309 
00310    if (dbsqlexec(dbproc) == FAIL) {
00311       return 1;
00312    }
00313 
00314    /* Consume the result set (we don't really care about the result, though) */
00315    while (dbresults(dbproc) != NO_MORE_RESULTS) {
00316       while (dbnextrow(dbproc) != NO_MORE_ROWS);
00317    }
00318 
00319    return 0;
00320 }

static void get_date ( char *  dateField,
size_t  len,
struct timeval  when 
) [static]

Definition at line 279 of file cdr_tds.c.

References ast_copy_string(), ast_localtime(), ast_strftime(), ast_tvzero(), and DATE_FORMAT.

00280 {
00281    /* To make sure we have date variable if not insert null to SQL */
00282    if (!ast_tvzero(when)) {
00283       struct ast_tm tm;
00284       ast_localtime(&when, &tm, NULL);
00285       ast_strftime(dateField, len, "'" DATE_FORMAT "'", &tm);
00286    } else {
00287       ast_copy_string(dateField, "null", len);
00288    }
00289 }

static int load_module ( void   )  [static]

Definition at line 531 of file cdr_tds.c.

References ast_calloc, ast_cdr_register(), ast_free, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_string_field_free_memory, ast_string_field_init, dbinit(), LOG_ERROR, tds_error_handler(), tds_load_module(), tds_log(), and tds_message_handler().

00532 {
00533    if (dbinit() == FAIL) {
00534       ast_log(LOG_ERROR, "Failed to initialize FreeTDS db-lib\n");
00535       return AST_MODULE_LOAD_DECLINE;
00536    }
00537 
00538    dberrhandle(tds_error_handler);
00539    dbmsghandle(tds_message_handler);
00540 
00541    settings = ast_calloc(1, sizeof(*settings));
00542 
00543    if (!settings || ast_string_field_init(settings, 256)) {
00544       if (settings) {
00545          ast_free(settings);
00546          settings = NULL;
00547       }
00548       dbexit();
00549       return AST_MODULE_LOAD_DECLINE;
00550    }
00551 
00552    if (!tds_load_module(0)) {
00553       ast_string_field_free_memory(settings);
00554       ast_free(settings);
00555       settings = NULL;
00556       dbexit();
00557       return AST_MODULE_LOAD_DECLINE;
00558    }
00559 
00560    ast_cdr_register(name, ast_module_info->description, tds_log);
00561 
00562    return AST_MODULE_LOAD_SUCCESS;
00563 }

static int mssql_connect ( void   )  [static]

Definition at line 334 of file cdr_tds.c.

References ast_log(), cdr_tds_config::charset, cdr_tds_config::connected, cdr_tds_config::database, cdr_tds_config::dbproc, execute_and_consume(), cdr_tds_config::has_userfield, cdr_tds_config::hostname, cdr_tds_config::language, LOG_ERROR, LOG_NOTICE, cdr_tds_config::password, cdr_tds_config::table, and cdr_tds_config::username.

Referenced by tds_load_module(), and tds_log().

00335 {
00336    LOGINREC *login;
00337 
00338    if ((login = dblogin()) == NULL) {
00339       ast_log(LOG_ERROR, "Unable to allocate login structure for db-lib\n");
00340       return -1;
00341    }
00342 
00343    DBSETLAPP(login,     "TSQL");
00344    DBSETLUSER(login,    (char *) settings->username);
00345    DBSETLPWD(login,     (char *) settings->password);
00346    DBSETLCHARSET(login, (char *) settings->charset);
00347    DBSETLNATLANG(login, (char *) settings->language);
00348 
00349    if ((settings->dbproc = dbopen(login, (char *) settings->hostname)) == NULL) {
00350       ast_log(LOG_ERROR, "Unable to connect to %s\n", settings->hostname);
00351       dbloginfree(login);
00352       return -1;
00353    }
00354 
00355    dbloginfree(login);
00356 
00357    if (dbuse(settings->dbproc, (char *) settings->database) == FAIL) {
00358       ast_log(LOG_ERROR, "Unable to select database %s\n", settings->database);
00359       goto failed;
00360    }
00361 
00362    if (execute_and_consume(settings->dbproc, "SELECT 1 FROM [%s]", settings->table)) {
00363       ast_log(LOG_ERROR, "Unable to find table '%s'\n", settings->table);
00364       goto failed;
00365    }
00366 
00367    /* Check to see if we have a userfield column in the table */
00368    if (execute_and_consume(settings->dbproc, "SELECT userfield FROM [%s] WHERE 1 = 0", settings->table)) {
00369       ast_log(LOG_NOTICE, "Unable to find 'userfield' column in table '%s'\n", settings->table);
00370       settings->has_userfield = 0;
00371    } else {
00372       settings->has_userfield = 1;
00373    }
00374 
00375    settings->connected = 1;
00376 
00377    return 0;
00378 
00379 failed:
00380    dbclose(settings->dbproc);
00381    settings->dbproc = NULL;
00382    return -1;
00383 }

static int mssql_disconnect ( void   )  [static]

Definition at line 322 of file cdr_tds.c.

References cdr_tds_config::connected, and cdr_tds_config::dbproc.

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

00323 {
00324    if (settings->dbproc) {
00325       dbclose(settings->dbproc);
00326       settings->dbproc = NULL;
00327    }
00328 
00329    settings->connected = 0;
00330 
00331    return 0;
00332 }

static int reload ( void   )  [static]

Definition at line 526 of file cdr_tds.c.

References tds_load_module().

00527 {
00528    return tds_load_module(1);
00529 }

static int tds_error_handler ( DBPROCESS *  dbproc,
int  severity,
int  dberr,
int  oserr,
char *  dberrstr,
char *  oserrstr 
) [static]

Definition at line 403 of file cdr_tds.c.

References ast_log(), and LOG_ERROR.

Referenced by load_module().

00404 {
00405    ast_log(LOG_ERROR, "%s (%d)\n", dberrstr, dberr);
00406 
00407    if (oserr != DBNOERR) {
00408       ast_log(LOG_ERROR, "%s (%d)\n", oserrstr, oserr);
00409    }
00410 
00411    return INT_CANCEL;
00412 }

static int tds_load_module ( int  reload  )  [static]

Definition at line 422 of file cdr_tds.c.

References ast_config_destroy(), ast_config_load, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_string_field_init, ast_string_field_set, ast_variable_browse(), ast_variable_retrieve(), charset, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, hostname, language, LOG_ERROR, LOG_NOTICE, mssql_connect(), mssql_disconnect(), table, and tds_lock.

Referenced by load_module(), and reload().

00423 {
00424    struct ast_config *cfg;
00425    const char *ptr = NULL;
00426    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00427 
00428    cfg = ast_config_load(config, config_flags);
00429    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
00430       ast_log(LOG_NOTICE, "Unable to load TDS config for CDRs: %s\n", config);
00431       return 0;
00432    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00433       return 0;
00434 
00435    if (!ast_variable_browse(cfg, "global")) {
00436       /* nothing configured */
00437       ast_config_destroy(cfg);
00438       return 0;
00439    }
00440 
00441    ast_mutex_lock(&tds_lock);
00442 
00443    /* Clear out any existing settings */
00444    ast_string_field_init(settings, 0);
00445 
00446    /* 'connection' is the new preferred configuration option */
00447    ptr = ast_variable_retrieve(cfg, "global", "connection");
00448    if (ptr) {
00449       ast_string_field_set(settings, hostname, ptr);
00450    } else {
00451       /* But we keep 'hostname' for backwards compatibility */
00452       ptr = ast_variable_retrieve(cfg, "global", "hostname");
00453       if (ptr) {
00454          ast_string_field_set(settings, hostname, ptr);
00455       } else {
00456          ast_log(LOG_ERROR, "Failed to connect: Database server connection not specified.\n");
00457          goto failed;
00458       }
00459    }
00460 
00461    ptr = ast_variable_retrieve(cfg, "global", "dbname");
00462    if (ptr) {
00463       ast_string_field_set(settings, database, ptr);
00464    } else {
00465       ast_log(LOG_ERROR, "Failed to connect: Database dbname not specified.\n");
00466       goto failed;
00467    }
00468 
00469    ptr = ast_variable_retrieve(cfg, "global", "user");
00470    if (ptr) {
00471       ast_string_field_set(settings, username, ptr);
00472    } else {
00473       ast_log(LOG_ERROR, "Failed to connect: Database dbuser not specified.\n");
00474       goto failed;
00475    }
00476 
00477    ptr = ast_variable_retrieve(cfg, "global", "password");
00478    if (ptr) {
00479       ast_string_field_set(settings, password, ptr);
00480    } else {
00481       ast_log(LOG_ERROR, "Failed to connect: Database password not specified.\n");
00482       goto failed;
00483    }
00484 
00485    ptr = ast_variable_retrieve(cfg, "global", "charset");
00486    if (ptr) {
00487       ast_string_field_set(settings, charset, ptr);
00488    } else {
00489       ast_string_field_set(settings, charset, "iso_1");
00490    }
00491 
00492    ptr = ast_variable_retrieve(cfg, "global", "language");
00493    if (ptr) {
00494       ast_string_field_set(settings, language, ptr);
00495    } else {
00496       ast_string_field_set(settings, language, "us_english");
00497    }
00498 
00499    ptr = ast_variable_retrieve(cfg, "global", "table");
00500    if (ptr) {
00501       ast_string_field_set(settings, table, ptr);
00502    } else {
00503       ast_log(LOG_NOTICE, "Table name not specified, using 'cdr' by default.\n");
00504       ast_string_field_set(settings, table, "cdr");
00505    }
00506 
00507    mssql_disconnect();
00508 
00509    if (mssql_connect()) {
00510       /* We failed to connect (mssql_connect takes care of logging it) */
00511       goto failed;
00512    }
00513 
00514    ast_mutex_unlock(&tds_lock);
00515    ast_config_destroy(cfg);
00516 
00517    return 1;
00518 
00519 failed:
00520    ast_mutex_unlock(&tds_lock);
00521    ast_config_destroy(cfg);
00522 
00523    return 0;
00524 }

static int tds_log ( struct ast_cdr cdr  )  [static]

Definition at line 111 of file cdr_tds.c.

References accountcode, anti_injection(), ast_cdr_disp2str(), ast_cdr_flags2str(), ast_free, ast_log(), AST_MAX_USER_FIELD, ast_mutex_lock(), ast_mutex_unlock(), cdr_tds_config::connected, cdr_tds_config::dbproc, get_date(), cdr_tds_config::has_userfield, cdr_tds_config::hostname, LOG_ERROR, LOG_NOTICE, mssql_connect(), mssql_disconnect(), cdr_tds_config::table, and tds_lock.

Referenced by load_module().

00112 {
00113    char start[80], answer[80], end[80];
00114    char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid, *userfield = NULL;
00115    RETCODE erc;
00116    int res = -1;
00117    int attempt = 1;
00118 
00119    accountcode = anti_injection(cdr->accountcode, 20);
00120    src         = anti_injection(cdr->src, 80);
00121    dst         = anti_injection(cdr->dst, 80);
00122    dcontext    = anti_injection(cdr->dcontext, 80);
00123    clid        = anti_injection(cdr->clid, 80);
00124    channel     = anti_injection(cdr->channel, 80);
00125    dstchannel  = anti_injection(cdr->dstchannel, 80);
00126    lastapp     = anti_injection(cdr->lastapp, 80);
00127    lastdata    = anti_injection(cdr->lastdata, 80);
00128    uniqueid    = anti_injection(cdr->uniqueid, 32);
00129 
00130    get_date(start, sizeof(start), cdr->start);
00131    get_date(answer, sizeof(answer), cdr->answer);
00132    get_date(end, sizeof(end), cdr->end);
00133 
00134    ast_mutex_lock(&tds_lock);
00135 
00136    if (settings->has_userfield) {
00137       userfield = anti_injection(cdr->userfield, AST_MAX_USER_FIELD);
00138    }
00139 
00140 retry:
00141    /* Ensure that we are connected */
00142    if (!settings->connected) {
00143       ast_log(LOG_NOTICE, "Attempting to reconnect to %s (Attempt %d)\n", settings->hostname, attempt);
00144       if (mssql_connect()) {
00145          /* Connect failed */
00146          if (attempt++ < 3) {
00147             goto retry;
00148          }
00149          goto done;
00150       }
00151    }
00152 
00153    if (settings->has_userfield) {
00154       erc = dbfcmd(settings->dbproc,
00155                 "INSERT INTO %s "
00156                 "("
00157                 "accountcode, src, dst, dcontext, clid, channel, "
00158                 "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
00159                 "billsec, disposition, amaflags, uniqueid, userfield"
00160                 ") "
00161                 "VALUES "
00162                 "("
00163                 "'%s', '%s', '%s', '%s', '%s', '%s', "
00164                 "'%s', '%s', '%s', %s, %s, %s, %ld, "
00165                 "%ld, '%s', '%s', '%s', '%s'"
00166                 ")",
00167                 settings->table,
00168                 accountcode, src, dst, dcontext, clid, channel,
00169                 dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
00170                 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid,
00171                 userfield
00172          );
00173    } else {
00174       erc = dbfcmd(settings->dbproc,
00175                 "INSERT INTO %s "
00176                 "("
00177                 "accountcode, src, dst, dcontext, clid, channel, "
00178                 "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
00179                 "billsec, disposition, amaflags, uniqueid"
00180                 ") "
00181                 "VALUES "
00182                 "("
00183                 "'%s', '%s', '%s', '%s', '%s', '%s', "
00184                 "'%s', '%s', '%s', %s, %s, %s, %ld, "
00185                 "%ld, '%s', '%s', '%s'"
00186                 ")",
00187                 settings->table,
00188                 accountcode, src, dst, dcontext, clid, channel,
00189                 dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
00190                 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid
00191          );
00192    }
00193 
00194    if (erc == FAIL) {
00195       if (attempt++ < 3) {
00196          ast_log(LOG_NOTICE, "Failed to build INSERT statement, retrying...\n");
00197          mssql_disconnect();
00198          goto retry;
00199       } else {
00200          ast_log(LOG_ERROR, "Failed to build INSERT statement, no CDR was logged.\n");
00201          goto done;
00202       }
00203    }
00204 
00205    if (dbsqlexec(settings->dbproc) == FAIL) {
00206       if (attempt++ < 3) {
00207          ast_log(LOG_NOTICE, "Failed to execute INSERT statement, retrying...\n");
00208          mssql_disconnect();
00209          goto retry;
00210       } else {
00211          ast_log(LOG_ERROR, "Failed to execute INSERT statement, no CDR was logged.\n");
00212          goto done;
00213       }
00214    }
00215 
00216    /* Consume any results we might get back (this is more of a sanity check than
00217     * anything else, since an INSERT shouldn't return results). */
00218    while (dbresults(settings->dbproc) != NO_MORE_RESULTS) {
00219       while (dbnextrow(settings->dbproc) != NO_MORE_ROWS);
00220    }
00221 
00222    res = 0;
00223 
00224 done:
00225    ast_mutex_unlock(&tds_lock);
00226 
00227    ast_free(accountcode);
00228    ast_free(src);
00229    ast_free(dst);
00230    ast_free(dcontext);
00231    ast_free(clid);
00232    ast_free(channel);
00233    ast_free(dstchannel);
00234    ast_free(lastapp);
00235    ast_free(lastdata);
00236    ast_free(uniqueid);
00237 
00238    if (userfield) {
00239       ast_free(userfield);
00240    }
00241 
00242    return res;
00243 }

static int tds_message_handler ( DBPROCESS *  dbproc,
DBINT  msgno,
int  msgstate,
int  severity,
char *  msgtext,
char *  srvname,
char *  procname,
int  line 
) [static]

Definition at line 414 of file cdr_tds.c.

References ast_debug, ast_log(), and LOG_NOTICE.

Referenced by load_module().

00415 {
00416    ast_debug(1, "Msg %d, Level %d, State %d, Line %d\n", msgno, severity, msgstate, line);
00417    ast_log(LOG_NOTICE, "%s\n", msgtext);
00418 
00419    return 0;
00420 }

static int tds_unload_module ( void   )  [static]

Definition at line 385 of file cdr_tds.c.

References ast_cdr_unregister(), ast_free, ast_mutex_lock(), ast_mutex_unlock(), ast_string_field_free_memory, mssql_disconnect(), and tds_lock.

Referenced by unload_module().

00386 {
00387    if (settings) {
00388       ast_mutex_lock(&tds_lock);
00389       mssql_disconnect();
00390       ast_mutex_unlock(&tds_lock);
00391 
00392       ast_string_field_free_memory(settings);
00393       ast_free(settings);
00394    }
00395 
00396    ast_cdr_unregister(name);
00397 
00398    dbexit();
00399 
00400    return 0;
00401 }

static int unload_module ( void   )  [static]

Definition at line 565 of file cdr_tds.c.

References tds_unload_module().

00566 {
00567    return tds_unload_module();
00568 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "FreeTDS CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 574 of file cdr_tds.c.

Definition at line 574 of file cdr_tds.c.

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

Definition at line 81 of file cdr_tds.c.

char* name = "FreeTDS (MSSQL)" [static]

Definition at line 80 of file cdr_tds.c.

struct cdr_tds_config* settings [static]

Definition at line 100 of file cdr_tds.c.

ast_mutex_t tds_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

Definition at line 98 of file cdr_tds.c.

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


Generated on Wed Oct 28 13:31:56 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6