Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Functions | Variables
cdr_tds.c File Reference

FreeTDS CDR logger. More...

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

Macros

#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)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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_LOAD_ORDER , .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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, .requires = "cdr", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static const char config [] = "cdr_tds.conf"
 
static const char name [] = "FreeTDS (MSSQL)"
 
static struct cdr_tds_configsettings
 
static ast_mutex_t tds_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 

Detailed Description

FreeTDS CDR logger.

See also

Definition in file cdr_tds.c.

Macro Definition Documentation

◆ DATE_FORMAT

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

Referenced by get_date().

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 639 of file cdr_tds.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 639 of file cdr_tds.c.

◆ anti_injection()

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

Definition at line 302 of file cdr_tds.c.

References ast_calloc, ast_log, buf, len(), LOG_ERROR, NULL, str, and strcasestr().

Referenced by tds_log().

303 {
304  /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */
305  char *buf;
306  char *buf_ptr, *srh_ptr;
307  char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"};
308  int idx;
309 
310  if (!(buf = ast_calloc(1, len + 1))) {
311  ast_log(LOG_ERROR, "Out of memory\n");
312  return NULL;
313  }
314 
315  buf_ptr = buf;
316 
317  /* Escape single quotes */
318  for (; *str && strlen(buf) < len; str++) {
319  if (*str == '\'') {
320  *buf_ptr++ = '\'';
321  }
322  *buf_ptr++ = *str;
323  }
324  *buf_ptr = '\0';
325 
326  /* Erase known bad input */
327  for (idx = 0; *known_bad[idx]; idx++) {
328  while ((srh_ptr = strcasestr(buf, known_bad[idx]))) {
329  memmove(srh_ptr, srh_ptr + strlen(known_bad[idx]), strlen(srh_ptr + strlen(known_bad[idx])) + 1);
330  }
331  }
332 
333  return buf;
334 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char * strcasestr(const char *, const char *)
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 639 of file cdr_tds.c.

◆ execute_and_consume()

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

Definition at line 348 of file cdr_tds.c.

References ast_free, and ast_vasprintf.

Referenced by mssql_connect().

349 {
350  va_list ap;
351  char *buffer;
352 
353  va_start(ap, fmt);
354  if (ast_vasprintf(&buffer, fmt, ap) < 0) {
355  va_end(ap);
356  return 1;
357  }
358  va_end(ap);
359 
360  if (dbfcmd(dbproc, buffer) == FAIL) {
361  ast_free(buffer);
362  return 1;
363  }
364 
365  ast_free(buffer);
366 
367  if (dbsqlexec(dbproc) == FAIL) {
368  return 1;
369  }
370 
371  /* Consume the result set (we don't really care about the result, though) */
372  while (dbresults(dbproc) != NO_MORE_RESULTS) {
373  while (dbnextrow(dbproc) != NO_MORE_ROWS);
374  }
375 
376  return 0;
377 }
#define ast_vasprintf(ret, fmt, ap)
A wrapper for vasprintf()
Definition: astmm.h:280
#define ast_free(a)
Definition: astmm.h:182

◆ get_date()

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

Definition at line 336 of file cdr_tds.c.

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

Referenced by tds_log().

337 {
338  /* To make sure we have date variable if not insert null to SQL */
339  if (!ast_tvzero(when)) {
340  struct ast_tm tm;
341  ast_localtime(&when, &tm, NULL);
342  ast_strftime(dateField, len, "'" DATE_FORMAT "'", &tm);
343  } else {
344  ast_copy_string(dateField, "null", len);
345  }
346 }
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
#define NULL
Definition: resample.c:96
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define DATE_FORMAT
Definition: cdr_tds.c:75
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401

◆ load_module()

static int load_module ( void  )
static

Definition at line 597 of file cdr_tds.c.

References ast_calloc_with_stringfields, ast_cdr_register(), ast_free, ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_string_field_free_memory, ast_module_info::description, LOG_ERROR, name, NULL, tds_error_handler(), tds_load_module(), tds_log(), and tds_message_handler().

Referenced by unload_module().

598 {
599  if (dbinit() == FAIL) {
600  ast_log(LOG_ERROR, "Failed to initialize FreeTDS db-lib\n");
602  }
603 
604  dberrhandle(tds_error_handler);
605  dbmsghandle(tds_message_handler);
606 
608 
609  if (!settings) {
610  dbexit();
612  }
613 
614  if (!tds_load_module(0)) {
617  settings = NULL;
618  dbexit();
620  }
621 
623 
625 }
const char * description
Definition: module.h:352
static int tds_log(struct ast_cdr *cdr)
Definition: cdr_tds.c:109
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:426
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
Definition: cdr.c:2943
#define LOG_ERROR
Definition: logger.h:285
static int tds_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
Definition: cdr_tds.c:462
#define ast_free(a)
Definition: astmm.h:182
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int tds_load_module(int reload)
Definition: cdr_tds.c:481
static const char name[]
Definition: cdr_tds.c:77
static struct cdr_tds_config * settings
Definition: cdr_tds.c:98
static int tds_message_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
Definition: cdr_tds.c:473
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368

◆ mssql_connect()

static int mssql_connect ( void  )
static

Definition at line 391 of file cdr_tds.c.

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

Referenced by tds_load_module(), and tds_log().

392 {
393  LOGINREC *login;
394 
395  if ((login = dblogin()) == NULL) {
396  ast_log(LOG_ERROR, "Unable to allocate login structure for db-lib\n");
397  return -1;
398  }
399 
400  DBSETLAPP(login, "TSQL");
401  DBSETLUSER(login, (char *) settings->username);
402  DBSETLPWD(login, (char *) settings->password);
403  DBSETLCHARSET(login, (char *) settings->charset);
404  DBSETLNATLANG(login, (char *) settings->language);
405 
406  if ((settings->dbproc = dbopen(login, (char *) settings->hostname)) == NULL) {
407  ast_log(LOG_ERROR, "Unable to connect to %s\n", settings->hostname);
408  dbloginfree(login);
409  return -1;
410  }
411 
412  dbloginfree(login);
413 
414  if (dbuse(settings->dbproc, (char *) settings->database) == FAIL) {
415  ast_log(LOG_ERROR, "Unable to select database %s\n", settings->database);
416  goto failed;
417  }
418 
419  if (execute_and_consume(settings->dbproc, "SELECT 1 FROM [%s] WHERE 1 = 0", settings->table)) {
420  ast_log(LOG_ERROR, "Unable to find table '%s'\n", settings->table);
421  goto failed;
422  }
423 
424  /* Check to see if we have a userfield column in the table */
425  if (execute_and_consume(settings->dbproc, "SELECT userfield FROM [%s] WHERE 1 = 0", settings->table)) {
426  ast_log(LOG_NOTICE, "Unable to find 'userfield' column in table '%s'\n", settings->table);
427  settings->has_userfield = 0;
428  } else {
429  settings->has_userfield = 1;
430  }
431 
432  settings->connected = 1;
433 
434  return 0;
435 
436 failed:
437  dbclose(settings->dbproc);
438  settings->dbproc = NULL;
439  return -1;
440 }
const ast_string_field hostname
Definition: cdr_tds.c:90
const ast_string_field table
Definition: cdr_tds.c:90
DBPROCESS * dbproc
Definition: cdr_tds.c:91
#define NULL
Definition: resample.c:96
const ast_string_field language
Definition: cdr_tds.c:90
#define ast_log
Definition: astobj2.c:42
static int execute_and_consume(DBPROCESS *dbproc, const char *fmt,...)
Definition: cdr_tds.c:348
unsigned int connected
Definition: cdr_tds.c:92
unsigned int has_userfield
Definition: cdr_tds.c:93
#define LOG_ERROR
Definition: logger.h:285
const ast_string_field username
Definition: cdr_tds.c:90
const ast_string_field password
Definition: cdr_tds.c:90
#define LOG_NOTICE
Definition: logger.h:263
const ast_string_field charset
Definition: cdr_tds.c:90
const ast_string_field database
Definition: cdr_tds.c:90
static struct cdr_tds_config * settings
Definition: cdr_tds.c:98
DB * dbopen(char *fname, int flags, int mode, DBTYPE type, const void *openinfo) const

◆ mssql_disconnect()

static int mssql_disconnect ( void  )
static

Definition at line 379 of file cdr_tds.c.

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

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

380 {
381  if (settings->dbproc) {
382  dbclose(settings->dbproc);
383  settings->dbproc = NULL;
384  }
385 
386  settings->connected = 0;
387 
388  return 0;
389 }
DBPROCESS * dbproc
Definition: cdr_tds.c:91
#define NULL
Definition: resample.c:96
unsigned int connected
Definition: cdr_tds.c:92
static struct cdr_tds_config * settings
Definition: cdr_tds.c:98

◆ reload()

static int reload ( void  )
static

Definition at line 592 of file cdr_tds.c.

References tds_load_module().

Referenced by unload_module().

593 {
594  return tds_load_module(1);
595 }
static int tds_load_module(int reload)
Definition: cdr_tds.c:481

◆ tds_error_handler()

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

Definition at line 462 of file cdr_tds.c.

References ast_log, and LOG_ERROR.

Referenced by load_module().

463 {
464  ast_log(LOG_ERROR, "%s (%d)\n", dberrstr, dberr);
465 
466  if (oserr != DBNOERR) {
467  ast_log(LOG_ERROR, "%s (%d)\n", oserrstr, oserr);
468  }
469 
470  return INT_CANCEL;
471 }
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285

◆ tds_load_module()

static int tds_load_module ( int  reload)
static

Definition at line 481 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_true(), ast_variable_browse(), ast_variable_retrieve(), config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, cdr_tds_config::database, cdr_tds_config::hostname, cdr_tds_config::hrtime, cdr_tds_config::language, LOG_ERROR, LOG_NOTICE, mssql_connect(), mssql_disconnect(), NULL, cdr_tds_config::password, cdr_tds_config::table, tds_lock, and cdr_tds_config::username.

Referenced by load_module(), and reload().

482 {
483  struct ast_config *cfg;
484  const char *ptr = NULL;
485  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
486 
487  cfg = ast_config_load(config, config_flags);
488  if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
489  ast_log(LOG_NOTICE, "Unable to load TDS config for CDRs: %s\n", config);
490  return 0;
491  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
492  return 0;
493 
494  if (!ast_variable_browse(cfg, "global")) {
495  /* nothing configured */
496  ast_config_destroy(cfg);
497  return 0;
498  }
499 
501 
502  /* Clear out any existing settings */
504 
505  /* 'connection' is the new preferred configuration option */
506  ptr = ast_variable_retrieve(cfg, "global", "connection");
507  if (ptr) {
509  } else {
510  /* But we keep 'hostname' for backwards compatibility */
511  ptr = ast_variable_retrieve(cfg, "global", "hostname");
512  if (ptr) {
514  } else {
515  ast_log(LOG_ERROR, "Failed to connect: Database server connection not specified.\n");
516  goto failed;
517  }
518  }
519 
520  ptr = ast_variable_retrieve(cfg, "global", "dbname");
521  if (ptr) {
522  ast_string_field_set(settings, database, ptr);
523  } else {
524  ast_log(LOG_ERROR, "Failed to connect: Database dbname not specified.\n");
525  goto failed;
526  }
527 
528  ptr = ast_variable_retrieve(cfg, "global", "user");
529  if (ptr) {
530  ast_string_field_set(settings, username, ptr);
531  } else {
532  ast_log(LOG_ERROR, "Failed to connect: Database dbuser not specified.\n");
533  goto failed;
534  }
535 
536  ptr = ast_variable_retrieve(cfg, "global", "password");
537  if (ptr) {
539  } else {
540  ast_log(LOG_ERROR, "Failed to connect: Database password not specified.\n");
541  goto failed;
542  }
543 
544  ptr = ast_variable_retrieve(cfg, "global", "charset");
545  if (ptr) {
547  } else {
549  }
550 
551  ptr = ast_variable_retrieve(cfg, "global", "language");
552  if (ptr) {
554  } else {
555  ast_string_field_set(settings, language, "us_english");
556  }
557 
558  ptr = ast_variable_retrieve(cfg, "global", "table");
559  if (ptr) {
561  } else {
562  ast_log(LOG_NOTICE, "Table name not specified, using 'cdr' by default.\n");
564  }
565 
566  ptr = ast_variable_retrieve(cfg, "global", "hrtime");
567  if (ptr && ast_true(ptr)) {
568  ast_string_field_set(settings, hrtime, ptr);
569  } else {
570  ast_log(LOG_NOTICE, "High Resolution Time not found, using integers for billsec and duration fields by default.\n");
571  }
572 
574 
575  if (mssql_connect()) {
576  /* We failed to connect (mssql_connect takes care of logging it) */
577  goto failed;
578  }
579 
581  ast_config_destroy(cfg);
582 
583  return 1;
584 
585 failed:
587  ast_config_destroy(cfg);
588 
589  return 0;
590 }
static const char config[]
Definition: cdr_tds.c:78
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
#define CONFIG_STATUS_FILEINVALID
static ast_mutex_t tds_lock
Definition: cdr_tds.c:96
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
static struct ast_str * password
Definition: cdr_mysql.c:77
static int mssql_connect(void)
Definition: cdr_tds.c:391
static char * table
Definition: cdr_odbc.c:58
static int reload(void)
Definition: cdr_tds.c:592
static int mssql_disconnect(void)
Definition: cdr_tds.c:379
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
static char language[MAX_LANGUAGE]
Definition: chan_alsa.c:117
#define CONFIG_STATUS_FILEUNCHANGED
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define LOG_NOTICE
Definition: logger.h:263
charset
Definition: chan_unistim.c:336
Structure used to handle boolean flags.
Definition: utils.h:199
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static struct ast_str * hostname
Definition: cdr_mysql.c:77
static struct cdr_tds_config * settings
Definition: cdr_tds.c:98
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514

◆ tds_log()

static int tds_log ( struct ast_cdr cdr)
static

Definition at line 109 of file cdr_tds.c.

References accountcode, answer(), anti_injection(), ast_cdr_disp2str(), ast_channel_amaflags2string(), ast_free, ast_log, AST_MAX_USER_FIELD, ast_mutex_lock, ast_mutex_unlock, ast_tvdiff_us(), ast_tvzero(), cdr_tds_config::connected, cdr_tds_config::dbproc, done, end, get_date(), cdr_tds_config::has_userfield, cdr_tds_config::hostname, cdr_tds_config::hrtime, LOG_ERROR, LOG_NOTICE, mssql_connect(), mssql_disconnect(), NULL, cdr_tds_config::table, and tds_lock.

Referenced by load_module().

110 {
111  char start[80], answer[80], end[80];
112  char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid, *userfield = NULL;
113  RETCODE erc;
114  int res = -1;
115  int attempt = 1;
116 
117  accountcode = anti_injection(cdr->accountcode, 20);
118  src = anti_injection(cdr->src, 80);
119  dst = anti_injection(cdr->dst, 80);
120  dcontext = anti_injection(cdr->dcontext, 80);
121  clid = anti_injection(cdr->clid, 80);
122  channel = anti_injection(cdr->channel, 80);
123  dstchannel = anti_injection(cdr->dstchannel, 80);
124  lastapp = anti_injection(cdr->lastapp, 80);
125  lastdata = anti_injection(cdr->lastdata, 80);
126  uniqueid = anti_injection(cdr->uniqueid, 32);
127 
128  get_date(start, sizeof(start), cdr->start);
129  get_date(answer, sizeof(answer), cdr->answer);
130  get_date(end, sizeof(end), cdr->end);
131 
133 
134  if (settings->has_userfield) {
135  userfield = anti_injection(cdr->userfield, AST_MAX_USER_FIELD);
136  }
137 
138 retry:
139  /* Ensure that we are connected */
140  if (!settings->connected) {
141  ast_log(LOG_NOTICE, "Attempting to reconnect to %s (Attempt %d)\n", settings->hostname, attempt);
142  if (mssql_connect()) {
143  /* Connect failed */
144  if (attempt++ < 3) {
145  goto retry;
146  }
147  goto done;
148  }
149  }
150 
151  if (settings->has_userfield) {
152  if (settings->hrtime) {
153  double hrbillsec = 0.0;
154  double hrduration;
155 
156  if (!ast_tvzero(cdr->answer)) {
157  hrbillsec = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
158  }
159  hrduration = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
160 
161  erc = dbfcmd(settings->dbproc,
162  "INSERT INTO %s "
163  "("
164  "accountcode, src, dst, dcontext, clid, channel, "
165  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
166  "billsec, disposition, amaflags, uniqueid, userfield"
167  ") "
168  "VALUES "
169  "("
170  "'%s', '%s', '%s', '%s', '%s', '%s', "
171  "'%s', '%s', '%s', %s, %s, %s, %lf, "
172  "%lf, '%s', '%s', '%s', '%s'"
173  ")",
174  settings->table,
175  accountcode, src, dst, dcontext, clid, channel,
176  dstchannel, lastapp, lastdata, start, answer, end, hrduration,
177  hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid,
178  userfield
179  );
180  } else {
181  erc = dbfcmd(settings->dbproc,
182  "INSERT INTO %s "
183  "("
184  "accountcode, src, dst, dcontext, clid, channel, "
185  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
186  "billsec, disposition, amaflags, uniqueid, userfield"
187  ") "
188  "VALUES "
189  "("
190  "'%s', '%s', '%s', '%s', '%s', '%s', "
191  "'%s', '%s', '%s', %s, %s, %s, %ld, "
192  "%ld, '%s', '%s', '%s', '%s'"
193  ")",
194  settings->table,
195  accountcode, src, dst, dcontext, clid, channel,
196  dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
198  userfield
199  );
200  }
201  } else {
202  if (settings->hrtime) {
203  double hrbillsec = 0.0;
204  double hrduration;
205 
206  if (!ast_tvzero(cdr->answer)) {
207  hrbillsec = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
208  }
209  hrduration = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
210 
211  erc = dbfcmd(settings->dbproc,
212  "INSERT INTO %s "
213  "("
214  "accountcode, src, dst, dcontext, clid, channel, "
215  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
216  "billsec, disposition, amaflags, uniqueid"
217  ") "
218  "VALUES "
219  "("
220  "'%s', '%s', '%s', '%s', '%s', '%s', "
221  "'%s', '%s', '%s', %s, %s, %s, %lf, "
222  "%lf, '%s', '%s', '%s'"
223  ")",
224  settings->table,
225  accountcode, src, dst, dcontext, clid, channel,
226  dstchannel, lastapp, lastdata, start, answer, end, hrduration,
227  hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid
228  );
229  } else {
230  erc = dbfcmd(settings->dbproc,
231  "INSERT INTO %s "
232  "("
233  "accountcode, src, dst, dcontext, clid, channel, "
234  "dstchannel, lastapp, lastdata, start, answer, [end], duration, "
235  "billsec, disposition, amaflags, uniqueid"
236  ") "
237  "VALUES "
238  "("
239  "'%s', '%s', '%s', '%s', '%s', '%s', "
240  "'%s', '%s', '%s', %s, %s, %s, %ld, "
241  "%ld, '%s', '%s', '%s'"
242  ")",
243  settings->table,
244  accountcode, src, dst, dcontext, clid, channel,
245  dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
247  );
248  }
249  }
250 
251  if (erc == FAIL) {
252  if (attempt++ < 3) {
253  ast_log(LOG_NOTICE, "Failed to build INSERT statement, retrying...\n");
255  goto retry;
256  } else {
257  ast_log(LOG_ERROR, "Failed to build INSERT statement, no CDR was logged.\n");
258  goto done;
259  }
260  }
261 
262  if (dbsqlexec(settings->dbproc) == FAIL) {
263  if (attempt++ < 3) {
264  ast_log(LOG_NOTICE, "Failed to execute INSERT statement, retrying...\n");
266  goto retry;
267  } else {
268  ast_log(LOG_ERROR, "Failed to execute INSERT statement, no CDR was logged.\n");
269  goto done;
270  }
271  }
272 
273  /* Consume any results we might get back (this is more of a sanity check than
274  * anything else, since an INSERT shouldn't return results). */
275  while (dbresults(settings->dbproc) != NO_MORE_RESULTS) {
276  while (dbnextrow(settings->dbproc) != NO_MORE_ROWS);
277  }
278 
279  res = 0;
280 
281 done:
283 
284  ast_free(accountcode);
285  ast_free(src);
286  ast_free(dst);
287  ast_free(dcontext);
288  ast_free(clid);
289  ast_free(channel);
290  ast_free(dstchannel);
291  ast_free(lastapp);
292  ast_free(lastdata);
293  ast_free(uniqueid);
294 
295  if (userfield) {
296  ast_free(userfield);
297  }
298 
299  return res;
300 }
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:428
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:308
static char * anti_injection(const char *, int)
Definition: cdr_tds.c:302
char dstchannel[AST_MAX_EXTENSION]
Definition: cdr.h:288
const ast_string_field hostname
Definition: cdr_tds.c:90
const ast_string_field table
Definition: cdr_tds.c:90
long int billsec
Definition: cdr.h:302
char dcontext[AST_MAX_EXTENSION]
Definition: cdr.h:284
static ast_mutex_t tds_lock
Definition: cdr_tds.c:96
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4418
DBPROCESS * dbproc
Definition: cdr_tds.c:91
const ast_string_field hrtime
Definition: cdr_tds.c:90
#define ast_mutex_lock(a)
Definition: lock.h:187
Definition: muted.c:95
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
static int mssql_connect(void)
Definition: cdr_tds.c:391
int done
Definition: test_amihooks.c:48
char lastdata[AST_MAX_EXTENSION]
Definition: cdr.h:292
long int amaflags
Definition: cdr.h:306
static int mssql_disconnect(void)
Definition: cdr_tds.c:379
#define ast_log
Definition: astobj2.c:42
unsigned int connected
Definition: cdr_tds.c:92
unsigned int has_userfield
Definition: cdr_tds.c:93
char uniqueid[AST_MAX_UNIQUEID]
Definition: cdr.h:314
char dst[AST_MAX_EXTENSION]
Definition: cdr.h:282
char channel[AST_MAX_EXTENSION]
Definition: cdr.h:286
static int answer(void *data)
Definition: chan_pjsip.c:682
struct timeval answer
Definition: cdr.h:296
char lastapp[AST_MAX_EXTENSION]
Definition: cdr.h:290
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3430
#define LOG_ERROR
Definition: logger.h:285
#define LOG_NOTICE
Definition: logger.h:263
struct timeval start
Definition: cdr.h:294
#define ast_free(a)
Definition: astmm.h:182
long int duration
Definition: cdr.h:300
char src[AST_MAX_EXTENSION]
Definition: cdr.h:280
struct timeval end
Definition: cdr.h:298
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:78
long int disposition
Definition: cdr.h:304
char clid[AST_MAX_EXTENSION]
Definition: cdr.h:278
static struct cdr_tds_config * settings
Definition: cdr_tds.c:98
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.h:318
#define ast_mutex_unlock(a)
Definition: lock.h:188
static void get_date(char *, size_t len, struct timeval)
Definition: cdr_tds.c:336
#define AST_MAX_USER_FIELD
Definition: channel.h:175

◆ tds_message_handler()

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

References ast_debug, ast_log, and LOG_NOTICE.

Referenced by load_module().

474 {
475  ast_debug(1, "Msg %d, Level %d, State %d, Line %d\n", msgno, severity, msgstate, line);
476  ast_log(LOG_NOTICE, "%s\n", msgtext);
477 
478  return 0;
479 }
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define LOG_NOTICE
Definition: logger.h:263
enum ast_security_event_severity severity

◆ tds_unload_module()

static int tds_unload_module ( void  )
static

Definition at line 442 of file cdr_tds.c.

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

Referenced by unload_module().

443 {
444  if (ast_cdr_unregister(name)) {
445  return -1;
446  }
447 
448  if (settings) {
452 
455  }
456 
457  dbexit();
458 
459  return 0;
460 }
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
Definition: cdr.c:2988
static ast_mutex_t tds_lock
Definition: cdr_tds.c:96
#define ast_mutex_lock(a)
Definition: lock.h:187
static int mssql_disconnect(void)
Definition: cdr_tds.c:379
#define ast_free(a)
Definition: astmm.h:182
static const char name[]
Definition: cdr_tds.c:77
static struct cdr_tds_config * settings
Definition: cdr_tds.c:98
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 627 of file cdr_tds.c.

References AST_MODFLAG_LOAD_ORDER, AST_MODPRI_CDR_DRIVER, AST_MODULE_INFO(), AST_MODULE_SUPPORT_EXTENDED, ASTERISK_GPL_KEY, load_module(), reload(), and tds_unload_module().

628 {
629  return tds_unload_module();
630 }
static int tds_unload_module(void)
Definition: cdr_tds.c:442

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, .requires = "cdr", }
static

Definition at line 639 of file cdr_tds.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 639 of file cdr_tds.c.

◆ config

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

Definition at line 78 of file cdr_tds.c.

Referenced by tds_load_module().

◆ name

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

Definition at line 77 of file cdr_tds.c.

Referenced by load_module(), and tds_unload_module().

◆ settings

struct cdr_tds_config* settings
static

Definition at line 98 of file cdr_tds.c.

Referenced by process_config().

◆ tds_lock

ast_mutex_t tds_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Definition at line 96 of file cdr_tds.c.

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