Wed Oct 28 11:51:48 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 567 of file cdr_tds.c.

static void __unreg_module ( void   )  [static]

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

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

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

References tds_load_module().

00520 {
00521    return tds_load_module(1);
00522 }

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_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) {
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    ptr = ast_variable_retrieve(cfg, "global", "hostname");
00447    if (ptr) {
00448       ast_string_field_set(settings, hostname, ptr);
00449    } else {
00450       ast_log(LOG_ERROR, "Failed to connect: Database server hostname not specified.\n");
00451       goto failed;
00452    }
00453 
00454    ptr = ast_variable_retrieve(cfg, "global", "dbname");
00455    if (ptr) {
00456       ast_string_field_set(settings, database, ptr);
00457    } else {
00458       ast_log(LOG_ERROR, "Failed to connect: Database dbname not specified.\n");
00459       goto failed;
00460    }
00461 
00462    ptr = ast_variable_retrieve(cfg, "global", "user");
00463    if (ptr) {
00464       ast_string_field_set(settings, username, ptr);
00465    } else {
00466       ast_log(LOG_ERROR, "Failed to connect: Database dbuser not specified.\n");
00467       goto failed;
00468    }
00469 
00470    ptr = ast_variable_retrieve(cfg, "global", "password");
00471    if (ptr) {
00472       ast_string_field_set(settings, password, ptr);
00473    } else {
00474       ast_log(LOG_ERROR, "Failed to connect: Database password not specified.\n");
00475       goto failed;
00476    }
00477 
00478    ptr = ast_variable_retrieve(cfg, "global", "charset");
00479    if (ptr) {
00480       ast_string_field_set(settings, charset, ptr);
00481    } else {
00482       ast_string_field_set(settings, charset, "iso_1");
00483    }
00484 
00485    ptr = ast_variable_retrieve(cfg, "global", "language");
00486    if (ptr) {
00487       ast_string_field_set(settings, language, ptr);
00488    } else {
00489       ast_string_field_set(settings, language, "us_english");
00490    }
00491 
00492    ptr = ast_variable_retrieve(cfg, "global", "table");
00493    if (ptr) {
00494       ast_string_field_set(settings, table, ptr);
00495    } else {
00496       ast_log(LOG_NOTICE, "Table name not specified, using 'cdr' by default.\n");
00497       ast_string_field_set(settings, table, "cdr");
00498    }
00499 
00500    mssql_disconnect();
00501 
00502    if (mssql_connect()) {
00503       /* We failed to connect (mssql_connect takes care of logging it) */
00504       goto failed;
00505    }
00506 
00507    ast_mutex_unlock(&tds_lock);
00508    ast_config_destroy(cfg);
00509 
00510    return 1;
00511 
00512 failed:
00513    ast_mutex_unlock(&tds_lock);
00514    ast_config_destroy(cfg);
00515 
00516    return 0;
00517 }

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

References tds_unload_module().

00559 {
00560    return tds_unload_module();
00561 }


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

Definition at line 567 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 11:51:48 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6